Screencast: Mit PJAX Bereiche aktualisieren

Häfig wird bei kleinsten Änderungen in Teilbereichen einer Seite die gesamte Seite erneut gerendert. Die führt zu „unnötigen“ Seiten-Generierungen die gespart werden können. PJAX kann neue oder aktualisierte Bereiche über AJAX holen und somit die Seite stets aktuell halten. Ryan zeigt diese Woche wie es eingesetzt werden kann.

 

Downloads in verschiedenen Formaten:

mp4
m4v
webm
ogg

 

Resourcen:

Gemfile

[ruby]
gem ‚pjax_rails‘
[/ruby]

app/assets/javascripts/application.js

[javascript]
//= require jquery.pjax
[/javascript]

layouts/application.html.erb

[html]
<div data-pjax-container>
<%= yield %>
</div>
[/html]

index.html.erb

[html]
<title><%= yield(:title) %></div>
[/html]

Gemfile

[ruby]
gem ‚rack-pjax‘
[/ruby]

config/application.rb

[ruby]
config.middleware.use Rack::Pjax
[/ruby]

bash

[bash]
mkdir -p vendor/assets/javascripts
curl https://raw.github.com/defunkt/jquery-pjax/master/jquery.pjax.js > vendor/assets/javascripts/jquery.pjax.js
[/bash]

app/assets/javascripts/application.js

[javascript]
//= require jquery.pjax
[/javascript]

products.js.coffee

[javascript]
jQuery ->
$(‚.product a‘).pjax(‚[data-pjax-container]‘)
[/javascript]

index.html.erb

[html]
<div data-pjax-container>

</div>
[/html]

Screencast: Virtuelle Maschinen mit Vagrant

Virtuelle Maschinen sind sehr praktisch um Umgebungen für Entwicklung und Tests aufzubauen. Mit Vagrant besteht die Möglichkeit diese automatisiert zu provisionieren und auf Wunsch so produktionsnah wie nötig aufzusetzen. Weiterhin können mit Virtuellen Maschinen eine gemeinsame Umgebung eingerichtet werden, damit alle Projektmitglieder auf der gleichen Umgebung arbeiten. Dadurch kann ggf. Fehler beim Übergang auf eine produktive Umgebung gemindert werden. Ryan zeigt in seinem Screencast wie Vagrant zum Aufsetzen von Virtuellen Maschinen auf Basis von Virtual-Box eingesetzt werden kann.

 

Downloads in verschiedenen Formaten:

mp4
m4v
webm
ogg

 

Resourcen:

Vagrantfile

[ruby]
config.vm.forward_port "rails", 3000, 3000
[/ruby]

Gemfile

[ruby]
gem ‚therubyracer‘
[/ruby]

bash

[bash]
# setup vagrant
gem install vagrant
vagrant box add lucid32 http://files.vagrantup.com/lucid32.box
rails new todo
cd todo
vagrant init lucid32
mate Vagrantfile
vagrant up
vagrant ssh

# inside virtual machine
whoami
cd /vagrant
ruby -v
sudo apt-get update
sudo apt-get install build-essential zlib1g-dev curl git-core sqlite3 libsqlite3-dev

# install rbenv and Ruby 1.9.2
git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
echo ‚export PATH="$HOME/.rbenv/bin:$PATH"‘ >> ~/.bash_profile
echo ‚eval "$(rbenv init -)"‘ >> ~/.bash_profile
source .bash_profile
git clone git://github.com/sstephenson/ruby-build.git
cd ruby-build/
sudo ./install.sh
rbenv install 1.9.2-p290

# get Rails running
cd /vagrant
gem install bundler
rbenv rehash
bundle
bundle exec rails s

# vagrant commands
vagrant reload
vagrant status
vagrant suspend
vagrant resume
vagrant halt
vagrant up
vagrant package
vagrant destroy
[/bash]

Screencast: SOAP Webservices mit Savon

Obwohl REST inzwischen für viele die erste Wahl bei Webservices ist, gibt es noch einige Dienste, die aus SOAP aufbauen. Im Gegensatz zu REST ist bei SOAP ein wenig mehr Aufwand nötig, um diese APIs konsumieren zu können. Savon ist ein Plugin um dem Entwicker bei dieser Arbeit zu unterstützen und die Verwendung der Dienste zu vereinfachen. Ryan zeigt in diesem Screencast wie es eingesetzt werden kann.

 

Downloads in verschiedenen Formaten:

mp4
m4v
webm
ogg

 

Resourcen:

Gemfile

[ruby]
gem ’savon‘
[/ruby]

rails console

[ruby]
client = Savon::Client.new("http://www.webservicex.net/uszip.asmx?WSDL")
client.wsdl.soap_actions
client.request :web, :get_info_by_zip, body: { "USZip" => "90210" }
[/ruby]

models/zip_code.rb

[ruby]
class ZipCode
attr_reader :state, :city, :area_code, :time_zone
def initialize(zip)
# Gyoku.convert_symbols_to :camelcase
client = Savon::Client.new("http://www.webservicex.net/uszip.asmx?WSDL")
response = client.request :web, :get_info_by_zip, body: { "USZip" => zip }
if response.success?
data = response.to_array(:get_info_by_zip_response, :get_info_by_zip_result, :new_data_set, :table).first
if data
@state = data[:state]
@city = data[:city]
@area_code = data[:area_code]
@time_zone = data[:time_zone]
end
end
end
end
[/ruby]

Screencast: Abrechnungen in Rails mit Stripe

Abrechnungen werden von verschiedenen Bezahlsystemen angeboten. Je nach Umfang der Anforderungen kann dies ein komplexe Integrationsarbeit erfordern. Stripe versucht an dieser Stelle zu helfen und den gesammten Prozess zu vereinfachen und ist zusätzlich relativ günstig. Ryan zeigt in seinem Screencast wie es installiert und eingesetzt werden kann.

 

Downloads in verschiedenen Formaten:

mp4
m4v
webm
ogg

 

Resourcen:

Gemfile

[ruby]
gem ’stripe‘
[/ruby]

config/initializers/stripe.rb

[ruby]
Stripe.api_key = "tGaNWsIG3Qy6zvXB8wv4rEcizJpSXjF4"
STRIPE_PUBLIC_KEY = "pk_KcSyS2qPWdT5SdrwkQg0vNSyhZgqP"
[/ruby]

layouts/application.html.erb

[html]
<%= javascript_include_tag "https://js.stripe.com/v1/", "application" %>
<%= tag :meta, :name => "stripe-key", :content => STRIPE_PUBLIC_KEY %>
[/html]

subscriptions/new.html.erb

[html]
<%= f.hidden_field :stripe_card_token %>

<div class="field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<% if @subscription.stripe_card_token.present? %>
Credit card has been provided.
<% else %>
<div class="field">
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_code, "Security Code on Card (CVV)" %>
<%= text_field_tag :card_code, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_month, "Card Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
</div>
<% end %>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
[/html]

app/assets/javascripts/subscriptions.js.coffee

[javascript]

jQuery ->
Stripe.setPublishableKey($(‚meta[name="stripe-key"]‘).attr(‚content‘))
subscription.setupForm()

subscription =
setupForm: ->
$(‚#new_subscription‘).submit ->
$(‚input[type=submit]‘).attr(‚disabled‘, true)
if $(‚#card_number‘).length
subscription.processCard()
false
else
true

processCard: ->
card =
number: $(‚#card_number‘).val()
cvc: $(‚#card_code‘).val()
expMonth: $(‚#card_month‘).val()
expYear: $(‚#card_year‘).val()
Stripe.createToken(card, subscription.handleStripeResponse)

handleStripeResponse: (status, response) ->
if status == 200
$(‚#subscription_stripe_card_token‘).val(response.id)
$(‚#new_subscription‘)[0].submit()
else
$(‚#stripe_error‘).text(response.error.message)
$(‚input[type=submit]‘).attr(‚disabled‘, false)
[/javascript]

controllers/subscriptions_controller.rb

[ruby]
def create
@subscription = Subscription.new(params[:subscription])
if @subscription.save_with_payment
redirect_to @subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
[/ruby]

models/subscription.rb

[ruby]
attr_accessor :stripe_card_token

def save_with_payment
if valid?
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
[/ruby]

bash

[bash]
rails g migration add_stripe_to_subscriptions stripe_customer_token:string
rake db:migrate
[/bash]

Screencast: Einführung in Draper

Draper ist ein gem mit dem das Decorator Pattern auf domain-getriebene Modelle auf einfache Weise angewendet werden kann. Dabei werden die meisten Helfer in ein objekt-orientieren Ansatz umgewandelt, Filter auf dem Presentation-Layer ermöglicht und eine Schnittstelle zwischen den Controllern und Views zur Verfügung gestellt. Ryan zeigt in diesem Screencast wie es installiert, konfiguriert und benutzt wird.

 

Downloads in verschiedenen Formaten:

mp4
m4v
webm
ogg

 

Resourcen:

bash

[bash]
rails g draper:decorator user
[/bash]

Gemfile

[ruby]
gem ‚draper‘
[/ruby]

app/decorators/user_decorator.rb

[ruby]
class UserDecorator < ApplicationDecorator
decorates :user
allows :username

def avatar
site_link h.image_tag("avatars/#{avatar_name}", class: "avatar")
end

def linked_name
site_link(model.full_name.present? ? model.full_name : model.username)
end

def website
handle_none model.url do
h.link_to model.url, model.url
end
end

def twitter
handle_none model.twitter_name do
h.link_to model.twitter_name, "http://twitter.com/#{model.twitter_name}"
end
end

def bio
handle_none model.bio do
markdown(model.bio)
end
end

def member_since
model.created_at.strftime("%B %e, %Y")
end

private

def handle_none(value)
if value.present?
yield
else
h.content_tag :span, "None given", class: "none"
end
end

def site_link(content)
h.link_to_if model.url.present?, content, model.url
end

def avatar_name
if model.avatar_image_name.present?
model.avatar_image_name
else
"default.png"
end
end
end
[/ruby]

app/decorators/application_decorator.rb

[ruby]
class ApplicationDecorator < Draper::Base
def markdown(text)
Redcarpet.new(text, :hard_wrap, :filter_html, :autolink).to_html.html_safe
end
end
[/ruby]

app/controllers/users_controller.rb

[ruby]
def show
@user = UserDecorator.find(params[:id])
end
[/ruby]

users/show.html.erb

[html]
<div id="profile">
<%= @user.avatar %>
<h1><%= @user.linked_name %></h1>
<dl>
<dt>Username:</dt>
<dd><%= @user.username %></dd>
<dt>Member Since:</dt>
<dd><%= @user.member_since %></dd>
<dt>Website:</dt>
<dd><%= @user.website %></dd>
<dt>Twitter:</dt>
<dd><%= @user.twitter %></dd>
<dt>Bio:</dt>
<dd><%= @user.bio %></dd>
</dl>
</div>
[/html]