Rails For Kids 2009
-
date post
11-Sep-2014 -
Category
Technology
-
view
16 -
download
1
description
Transcript of Rails For Kids 2009
Ruby on RailsEvolução
Tuesday, December 15, 2009
13 e 14Outubro
2009Tuesday, December 15, 2009
07/2004 0.5
12/2005 1.0
03/2006 1.1
01/2007 1.2
12/2007 2.0
06/2008 2.1
11/2008 2.2
03/2009 2.3
Tuesday, December 15, 2009
Rails 0.525/07/2004
Tuesday, December 15, 2009
• Action Pack
• Action Controller
• Action View
• Active Record
• Action Mailer
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Rails 1.013/12/2005
Tuesday, December 15, 2009
• db/schema.rb
• config/environment.rb
• lib/tasks (Rakefile)
• scripts (stubs)
• vendor/plugins
Tuesday, December 15, 2009
• 2 vezes mais rápido
• FCGI melhor
• Inflector
• session (ActiveRecordStore)
• rake freeze_gems
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Plugins/Gems
Tuesday, December 15, 2009
Annotate Models
> sudo gem install ctran-annotate_models> annotate
# == Schema Information## Table name: posts## id :integer not null, primary key# title :string(255)# body :text# created_at :datetime# updated_at :datetime#
class Post < ActiveRecord::Baseend
Tuesday, December 15, 2009
Rails 1.128/03/2006
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
RJS Templates (.rjs)
var Cart = { add: function(product_id) { Element.addClassName('product_' + product_id, 'incart') new Ajax.Request('/account/add_to_cart/' + product_id, { method: 'post', onComplete: Cart.refresh }) }, remove: function(product_id) { Element.removeClassName('product_' + product_id, 'incart') new Ajax.Request('/account/remove_from_cart/' + product_id, { method: 'post', onComplete: Cart.refresh }) }, refresh: function() { new Ajax.Updater('cartbox', '/products/cartbox') new Ajax.Updater('num_items', '/products/num_items') }}
Tuesday, December 15, 2009
RJS Templates (.rjs)
page['cartbox'].replace :partial => 'cart'page['num_items'].replace :partial => 'num_items'page["product_#{params[:id]}"].addClassName 'incart'
Tuesday, December 15, 2009
respond_to e to_xml
def create @comment = Comment.create(params[:id])
respond_to do |type| type.html { redirect_to :action => "index" } type.js type.xml do headers["Location"] = url_for(:action => "show", :id => @comment.id) @comment.to_xml end endend
Tuesday, December 15, 2009
respond_to e to_xml
def create @comment = Comment.create(params[:id])
respond_to do |type| type.html { redirect_to :action => "index" } type.js type.xml do headers["Location"] = url_for(:action => "show", :id => @comment.id) @comment.to_xml end endend
Tuesday, December 15, 2009
Plugins/Gems
Tuesday, December 15, 2009
Exception Notification
> script/plugin install git://github.com/rails/exception_notification.git
# config/initializers/exception.rbExceptionNotifier.sender_address = %("Application Error" <[email protected]>)
ExceptionNotifier.exception_recipients = %w([email protected] [email protected])
ExceptionNotifier.email_prefix = "[railssummit] "
# app/controllers/application_controller.rbclass ApplicationController < ActionController::Base include ExceptionNotifiable ...end
Tuesday, December 15, 2009
Exception Notification
> script/plugin install git://github.com/rails/exception_notification.git
# config/initializers/exception.rbExceptionNotifier.sender_address = %("Application Error" <[email protected]>)
ExceptionNotifier.exception_recipients = %w([email protected] [email protected])
ExceptionNotifier.email_prefix = "[railssummit] "
# app/controllers/application_controller.rbclass ApplicationController < ActionController::Base include ExceptionNotifiable ...end
Tuesday, December 15, 2009
Authlogic
> sudo gem install binarylogic-authlogic
UserSession.create(:login => "bjohnson", :password => "my password", :remember_me => true) session = UserSession.new(:login => "bjohnson", :password => "my password", :remember_me => true); session.save
UserSession.create(:openid_identifier => "identifier", :remember_me => true) # requires the authlogic-oid "add on" gem UserSession.create(my_user_object, true) # skip authentication and log the user in directly, # the true means "remember me"
Tuesday, December 15, 2009
Authlogic
• OpenID
• LDAP
• Facebook Connect
• OAuth (Twitter)
class User < ActiveRecord::Base acts_as_authenticend
Tuesday, December 15, 2009
Rails 1.219/01/2007
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Restful Resources
# GET /weblog# GET /weblog.xml# GET /weblog.rssclass WeblogController < ActionController::Base def index @posts = Post.find :all respond_to do |format| format.html format.xml { render :xml => @posts.to_xml } format.rss { render :action => "feed.rxml" } end endend
Tuesday, December 15, 2009
Custom Restful Actions
/comments/1;edit
Tuesday, December 15, 2009
Custom Restful Actions
/comments/1;edit
Tuesday, December 15, 2009
Unicode
Tuesday, December 15, 2009
Plugins/Gems
Tuesday, December 15, 2009
State Machines
class TrafficLight include AlterEgo
state :proceed, :default => true do handle :color { "green" } transition :to => :caution, :on => :cycle! end
state :caution do handle :color { "yellow" } transition :to => :stop, :on => :cycle! end
state :stop do handle :color { "red" } transition :to => :proceed, :on => :cycle! endend
Tuesday, December 15, 2009
State Machines
• Acts As State Machine (AASM)
• Alter Ego
• State-Fu
light = TrafficLight.newlight.color # => "green"light.cycle!light.color # => "yellow"light.cycle!light.color # => "red"light.cycle!light.color # => "green"
http://jmettraux.wordpress.com/2009/07/03/state-machine-workflow-engine/
Tuesday, December 15, 2009
Rails 2.007/12/2007
Tuesday, December 15, 2009
• from_xml e serialização json
• plugins retirados (acts_as_list, etc)
• with_scope (privado)
• - ActiveWebService + ActiveResource
• config/initializers
• debugger (ruby-debug)
• SQLite3 por padrão
Tuesday, December 15, 2009
Namespaced Routes
map.namespace(:admin) do |admin| admin.resources :products, :collection => { :inventory => :get }, :member => { :duplicate => :post }, :has_many => [ :tags, :images, :variants ]end
# /avatars/45 => AvatarsController#showmap.resources :avatars
# /people/5/avatar => AvatarsController#show map.resources :people, :has_one => :avatar
Tuesday, December 15, 2009
Mime-Types e Multi Views
# config/initializers/mime_types.rbMime.register_alias "text/html", :iphone
# app/controllers/application.rbclass ApplicationController < ActionController::Base before_filter :adjust_format_for_iphone
private def adjust_format_for_iphone if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/] request.format = :iphone end endend
Tuesday, December 15, 2009
Mime-Types e Multi Views
# config/initializers/mime_types.rbMime.register_alias "text/html", :iphone
# app/controllers/application.rbclass ApplicationController < ActionController::Base before_filter :adjust_format_for_iphone
private def adjust_format_for_iphone if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/] request.format = :iphone end endend
Tuesday, December 15, 2009
Mime-Types e Multi Views
# config/initializers/mime_types.rbMime.register_alias "text/html", :iphone
# app/controllers/application.rbclass ApplicationController < ActionController::Base before_filter :adjust_format_for_iphone
private def adjust_format_for_iphone if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/] request.format = :iphone end endend
Tuesday, December 15, 2009
Mime-Types e Multi Views
# app/controllers/posts_controller.rbclass PostsController < ApplicationController def index respond_to do |format| format.html # renders index.html.erb format.iphone # renders index.iphone.erb end endend
Tuesday, December 15, 2009
Mime-Types e Multi Views
# app/controllers/posts_controller.rbclass PostsController < ApplicationController def index respond_to do |format| format.html # renders index.html.erb format.iphone # renders index.iphone.erb end endend
Tuesday, December 15, 2009
HTTP Basic Authentication
class PostsController < ApplicationController before_filter :authenticate, :except => [ :index ]
def index render :text => "Everyone can see me!" end def edit render :text => "I’m not publicly accessible" end
private def authenticate authenticate_or_request_with_http_basic do |user_name, password| user_name == "dhh" && password == "secret" end endend
Tuesday, December 15, 2009
HTTP Basic Authentication
class PostsController < ApplicationController before_filter :authenticate, :except => [ :index ]
def index render :text => "Everyone can see me!" end def edit render :text => "I’m not publicly accessible" end
private def authenticate authenticate_or_request_with_http_basic do |user_name, password| user_name == "dhh" && password == "secret" end endend
Tuesday, December 15, 2009
proteção contra CSRF
class ApplicationController < ActionController::Base helper :all # include all helpers, all the time
# See ActionController::RequestForgeryProtection for # details # Uncomment the :secret if you're not using the # cookie session store protect_from_forgery # :secret => # '9b76dcad7de4d8eca67e9d53329006ac'end
Tuesday, December 15, 2009
proteção contra CSRF
class ApplicationController < ActionController::Base helper :all # include all helpers, all the time
# See ActionController::RequestForgeryProtection for # details # Uncomment the :secret if you're not using the # cookie session store protect_from_forgery # :secret => # '9b76dcad7de4d8eca67e9d53329006ac'end
Tuesday, December 15, 2009
Tratamento de Exceções
class PostsController < ApplicationController rescue_from User::NotAuthorized, :with => :deny_access
protected def deny_access ... endend
Tuesday, December 15, 2009
Tratamento de Exceções
class PostsController < ApplicationController rescue_from User::NotAuthorized, :with => :deny_access
protected def deny_access ... endend
Tuesday, December 15, 2009
Session Cookie Store
# Your secret key for verifying cookie session data # integrity. If you change this key, all old sessions # will become invalid! Make sure the secret is at least # 30 characters and all random, no regular words or you'll # be exposed to dictionary attacks. config.action_controller.session = { :session_key => '_my_app_session', :secret => 'ec54b1c89c810d5937ede6b2969ee227c7653ffaffb37927a71203ef9687928d256572ae5c8e66efbf0b9686103b597c3bae537b813fc838580c794248c428da' }
Tuesday, December 15, 2009
Sexy Migrations
create_table :people do |t| t.column, "account_id", :integer t.column, "first_name", :string, :null => false t.column, "last_name", :string, :null => false t.column, "description", :text t.column, "created_at", :datetime t.column, "updated_at", :datetimeend
create_table :people do |t| t.integer :account_id t.string :first_name, :last_name, :null => false t.text :description t.timestampsend
Tuesday, December 15, 2009
Foxy Fixtures
# sellers.ymlshopify: name: Shopify
# products.ymlpimp_cup: seller: shopify name: Pimp cup
Tuesday, December 15, 2009
Plugins/Gems
Tuesday, December 15, 2009
Acts as Taggable
# config/environments.rbconfig.gem "mbleigh-acts-as-taggable-on", :lib => "acts-as-taggable-on", :source => "http://gems.github.com" # app/models/user.rbclass User < ActiveRecord::Base acts_as_taggable_on :tags, :skills, :interests named_scope :by_join_date, :order => "created_at DESC"end
Tuesday, December 15, 2009
Acts as Taggable
# config/environments.rbconfig.gem "mbleigh-acts-as-taggable-on", :lib => "acts-as-taggable-on", :source => "http://gems.github.com" # app/models/user.rbclass User < ActiveRecord::Base acts_as_taggable_on :tags, :skills, :interests named_scope :by_join_date, :order => "created_at DESC"end
Tuesday, December 15, 2009
Acts as Taggable
@user.tag_list = "awesome, slick, hefty" @user.skill_list = "joking, clowning, boxing" @user.skill_list # => ["joking","clowning","boxing"]@user.save
# The better way (utilizes named_scope)User.tagged_with("awesome", :on => :tags) # => [@user]User.tagged_with("awesome", :on => :skills) # => []
User.tagged_with("awesome").by_dateUser.tagged_with("awesome").by_date.paginate( :page => params[:page], :per_page => 20)
Tuesday, December 15, 2009
Model Versions# config/environments.rbconfig.gem 'laserlemon-vestal_versions', :lib => 'vestal_versions', :source => 'http://gems.github.com'
> script/generate vestal_versions_migration> rake db:migrate
# app/model/user.rbclass User < ActiveRecord::Base versionedend
>> u.version=> 1>> u.update_attribute(:first_name, 'Stephen')=> true>> u.version=> 2>> u.revert_to(:first)=> 1
Tuesday, December 15, 2009
Model Versions# config/environments.rbconfig.gem 'laserlemon-vestal_versions', :lib => 'vestal_versions', :source => 'http://gems.github.com'
> script/generate vestal_versions_migration> rake db:migrate
# app/model/user.rbclass User < ActiveRecord::Base versionedend
>> u.version=> 1>> u.update_attribute(:first_name, 'Stephen')=> true>> u.version=> 2>> u.revert_to(:first)=> 1
Tuesday, December 15, 2009
Rails 2.101/06/2008
Tuesday, December 15, 2009
Time Zones
# config/environment.rbconfig.time_zone = 'UTC'
$ rake time:zones:local* UTC -06:00 *Central AmericaCentral Time (US & Canada)Guadalajara...
>> t = Task.find_by_name('foo')=> #< Task ... >>> t.alert_at=> Sun, 06 Apr 2008 10:30:00 CDT -05:00>> t.alert_at_before_type_cast=> "2008-04-06 15:30:00"
Tuesday, December 15, 2009
Dirty tracking
article = Article.find(:first)article.changed? # => false
article.title # => "Title"article.title = "New Title"article.title_changed? # => true
article.title_was #=> "Title"article.title_change #=> ["Title", "New Title"]
article.changed #=> ['title']article.changes #=> { 'title' => ["Title", "New Title"] }
article.changed? #=> truearticle.save #=> truearticle.changed? #=> false
Tuesday, December 15, 2009
Gem Dependencies
Rails::Initializer.run do |config| # Require the latest version of haml config.gem "haml"
config.gem "chronic", :version => '0.2.3'
config.gem "akitaonrails-locarails", :source => "http://gems.github.com"
config.gem "aws-s3", :lib => "aws/s3" end
# rake gems:install# rake gems:unpack
Tuesday, December 15, 2009
Named Scopes
class User < ActiveRecord::Base named_scope :active, :conditions => {:active => true} named_scope :inactive, :conditions => {:active => false} named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }end
# Standard usageUser.active # User.find(:all, :conditions => {:active => true})User.inactive # User.find(:all, :conditions => {:active => false})User.recent # User.find(:all, :conditions => ['created_at > ?', 1.week.ago])
# They're nest-able too!User.active.recent
# same as:# User.with_scope(:conditions => {:active => true}) do# User.find(:all, :conditions => ['created_at > ?', 1.week.ago])# end
Tuesday, December 15, 2009
migrações timestamped
> script/generate migration post create db/migrate/20080402122512_post.rb
Tuesday, December 15, 2009
Plugins/Gems
Tuesday, December 15, 2009
Paperclip
# db/migrate/001_add_avatar_columns_to_userrbclass AddAvatarColumnsToUser < ActiveRecord::Migration def self.up add_column :users, :avatar_file_name, :string add_column :users, :avatar_content_type, :string add_column :users, :avatar_file_size, :integer add_column :users, :avatar_updated_at, :datetime end ...end
# app/models/user.rbclass User < ActiveRecord::Base has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }end
# app/views/users/new.html.erb<% form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %> <%= form.file_field :avatar %><% end %>
Tuesday, December 15, 2009
Paperclip
# db/migrate/001_add_avatar_columns_to_userrbclass AddAvatarColumnsToUser < ActiveRecord::Migration def self.up add_column :users, :avatar_file_name, :string add_column :users, :avatar_content_type, :string add_column :users, :avatar_file_size, :integer add_column :users, :avatar_updated_at, :datetime end ...end
# app/models/user.rbclass User < ActiveRecord::Base has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }end
# app/views/users/new.html.erb<% form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %> <%= form.file_field :avatar %><% end %>
Tuesday, December 15, 2009
Rails 2.221/11/2008
Tuesday, December 15, 2009
i18n# config/locales/pt-BR.yml--- pt-BR: abbreviation: Abreviação access_denied: "Acesso Negado" account: Conta account_updated: "Conta Atualizada!" action: Ação actions: cancel: Cancelar create: Criar destroy: Destruir list: Lista listing: Listagem new: Nova update: Atualizar
Tuesday, December 15, 2009
i18n
flash[:notice] = I18n.t(:basket_successfully_cleared)
flash[:notice] = t('order_processed_successfully')
<tr> <th colspan="2"><%= t("item") %></th> <th><%= t("price") %></th> <th><%= t("qty") %></th> <th><%= t("total") %></th></tr>
Tuesday, December 15, 2009
E-Tag e Last-Modified
class ArticlesController < ApplicationController def show_with_respond_to_block @article = Article.find(params[:id]) # unless stale? => "304 Not Modified" if stale?(:last_modified => @article.published_at.utc, :etag => @article) respond_to do |wants| # normal response processing end end end def show_with_implied_render @article = Article.find(params[:id]) # If fresh => "304 Not Modified" fresh_when(:last_modified => @article.published_at.utc, :etag => @article) endend
Tuesday, December 15, 2009
E-Tag e Last-Modified
class ArticlesController < ApplicationController def show_with_respond_to_block @article = Article.find(params[:id]) # unless stale? => "304 Not Modified" if stale?(:last_modified => @article.published_at.utc, :etag => @article) respond_to do |wants| # normal response processing end end end def show_with_implied_render @article = Article.find(params[:id]) # If fresh => "304 Not Modified" fresh_when(:last_modified => @article.published_at.utc, :etag => @article) endend
Tuesday, December 15, 2009
E-Tag e Last-Modified
class ArticlesController < ApplicationController def show_with_respond_to_block @article = Article.find(params[:id]) # unless stale? => "304 Not Modified" if stale?(:last_modified => @article.published_at.utc, :etag => @article) respond_to do |wants| # normal response processing end end end def show_with_implied_render @article = Article.find(params[:id]) # If fresh => "304 Not Modified" fresh_when(:last_modified => @article.published_at.utc, :etag => @article) endend
Tuesday, December 15, 2009
Thread safe e Connection Pool (JRuby)
# config/environments/production.rb:config.threadsafe!
# config/database.ymldevelopment: adapter: mysql username: root database: myapp_dev pool: 10
Tuesday, December 15, 2009
Shallow Route Nesting
# config/routes.rbmap.resources :publishers, :shallow => true do |publisher| publisher.resources :magazines do |magazine| magazine.resources :photos endend
# /publishers/1 ==> publisher_path(1)# /publishers/1/magazines ==> publisher_magazines_path(1)# /magazines/2 ==> magazine_path(2)# /magazines/2/photos ==> magazines_photos_path(2)# /photos/3 ==> photo_path(3)
Tuesday, December 15, 2009
Memoization
# antesdef full_name @full_name ||= "#{first_name} #{last_name}"end
# depoisextend ActiveSupport::Memoizabledef full_name "#{first_name} #{last_name}"endmemoize :full_name
Tuesday, December 15, 2009
Delegates com Prefixes
class Vendor < ActiveRecord::Base has_one :account delegate :email, :password, :to => :account, :prefix => trueend# @vendor.account_email# @vendor.account_password
class Vendor < ActiveRecord::Base has_one :account delegate :email, :password, :to => :account, :prefix => :ownerend# @vendor.owner_email# @vendor.owner_password
Tuesday, December 15, 2009
Mailer Layouts
class UserMailer < ActionMailer::Base def registration(user) subject "You've registered" from "[email protected]" endend# layouts/user_mailer.html.erb
class UserMailer < ActionMailer::Base layout 'email' ...end# layouts/email.html.erb
Tuesday, December 15, 2009
Plugins/Gems
Tuesday, December 15, 2009
Brazilian Rails
sudo gem install brazilian-rails
>> require 'brazilian-rails'=> ["PROJECTS"]
>> Dinheiro.new(256.55).por_extenso=> "duzentos e cinquenta e seis reais e cinquenta e cinco centavos"
>> Cnpj.new("691036040001-60").to_s=> "69.103.604/0001-60"
>> Date.new(2009,1,25).to_s_br=> "25/01/2009"
>> Time.new.strftime("%B")=> "Setembro"
Tuesday, December 15, 2009
Translated Routes
# locales/i18n_routes.ymles: edit: editar new: crear users: usuarios # config/routes.rbActionController::Routing::Routes.draw do |map| map.resources :users map.root :controller => 'users'end
#ActionController::Routing::Translator.i18nActionController::Routing::Translator.translate_from_file 'locales', 'i18n-routes.yml'
# app/controllers/application_controller.rbclass ApplicationController < ActionController::Base before_filter :set_locale_from_url ...end
Tuesday, December 15, 2009
Translated Routes
> script/plugin install git://github.com/raul/translate_routes.git
> rake routes
users_es GET /es/usuarios(.:format) {:action=>"index", ..:locale=>"es"} users_en GET /users(.:format) {:action=>"index", ..:locale=>"en"} POST /es/usuarios(.:format) {:action=>"create", ..:locale=>"es"} POST /users(.:format) {:action=>"create", ..:locale=>"en"} new_user_es GET /es/usuarios/crear(.:format) {:action=>"new", ..:locale=>"es"} new_user_en GET /users/new(.:format) {:action=>"new", ..:locale=>"en"}edit_user_es GET /es/usuarios/:id/editar(.:format) {:action=>"edit", ..:locale=>"es"}edit_user_en GET /users/:id/edit(.:format) {:action=>"edit", ..:locale=>"en"} user_es GET /es/usuarios/:id(.:format) {:action=>"show", ..:locale=>"es"} user_en GET /users/:id(.:format) {:action=>"show", ..:locale=>"en"} PUT /es/usuarios/:id(.:format) {:action=>"update", ..:locale=>"es"} PUT /users/:id(.:format) {:action=>"update", ..:locale=>"en"} DELETE /es/usuarios/:id(.:format) {:action=>"destroy", ..:locale=>"es"} DELETE /users/:id(.:format) {:action=>"destroy", ..:locale=>"en"} root_es /es {..:action=>"index", :locale=>"es"} root_en / {..:action=>"index", :locale=>"en"}
Tuesday, December 15, 2009
Rails 2.316/03/2009
Tuesday, December 15, 2009
• Rails Engines (limitado)
• Suporte Ruby 1.9.1
• Rack-based Lazy-loaded Sessions
• Quieter Backtrace
• Localized Views (show.da.html.erb)
• MySQL Conn. Reconnection
• Seed Data (db/seeds.rb)
Tuesday, December 15, 2009
Rack Support
> rake middleware
use Rack::Lockuse ActionController::Failsafeuse ActionController::Session::CookieStoreuse ActionController::ParamsParseruse Rack::MethodOverrideuse Rack::Headuse ActiveRecord::ConnectionAdapters::ConnectionManagementuse ActiveRecord::QueryCacherun ActionController::Dispatcher.new
Tuesday, December 15, 2009
Rails Metal
# app/metal/poller.rbclass Poller < Rails::Rack::Metal def call(env) if env["PATH_INFO"] =~ /^\/poller/ [200, {"Content-Type" => "text/html"}, "Hello, World!"] else [404, {"Content-Type" => "text/html"}, "Not Found"] end endend
# app/controllers/old_poller_controller.rbclass OldPollerController < ApplicationController def poller render :text => "Hello World!" endend
Tuesday, December 15, 2009
Rails Metal
# benchmark the traditional controller$ ab -n 1000 http://127.0.0.1:3000/old_poller/pollerRequests per second: 408.45 [#/sec] (mean)Time per request: 2.448 [ms] (mean)
# benchmark the Metal middleware$ ab -n 1000 http://127.0.0.1:3000/pollerRequests per second: 1154.66 [#/sec] (mean)Time per request: 0.866 [ms] (mean)
Tuesday, December 15, 2009
Nested Model Forms
<% form_for @project do |project_form| %> <div> <%= project_form.label :name, 'Project name:' %> <%= project_form.text_field :name %> </div>
<% @project.tasks.each do |task| %> <% new_or_existing = task.new_record? ? 'new' : 'existing' %> <% prefix = "project[#{new_or_existing}_task_attributes][]" %> <% fields_for prefix, task do |task_form| %> <p> <div> <%= task_form.label :name, 'Task:' %> <%= task_form.text_field :name %> </div>
<% unless task.new_record? %> <div> <%= task_form.label :_delete, 'Remove:' %> <%= task_form.check_box :_delete %> </div> <% end %> </p> <% end %> <% end %>
<%= project_form.submit %><% end %>
Tuesday, December 15, 2009
Nested Model Forms
<% form_for @project do |project_form| %> <div> <%= project_form.label :name, 'Project name:' %> <%= project_form.text_field :name %> </div>
<% @project.tasks.each do |task| %> <% new_or_existing = task.new_record? ? 'new' : 'existing' %> <% prefix = "project[#{new_or_existing}_task_attributes][]" %> <% fields_for prefix, task do |task_form| %> <p> <div> <%= task_form.label :name, 'Task:' %> <%= task_form.text_field :name %> </div>
<% unless task.new_record? %> <div> <%= task_form.label :_delete, 'Remove:' %> <%= task_form.check_box :_delete %> </div> <% end %> </p> <% end %> <% end %>
<%= project_form.submit %><% end %>
Tuesday, December 15, 2009
Nested Model Formsclass Project < ActiveRecord::Base after_update :save_tasks validates_associated :tasks
def new_task_attributes=(task_attributes) task_attributes.each { |attr| tasks.build(attr) } end
def existing_task_attributes=(task_attributes) tasks.reject(&:new_record?).each do |task| attributes = task_attributes[task.id.to_s] if attributes['_delete'] == '1' tasks.delete(task) else task.attributes = attributes end end end
private def save_tasks tasks.each { |task| task.save(false)} endend
Tuesday, December 15, 2009
Nested Model Forms
class Project < ActiveRecord::Base has_many :tasks
accept_nested_attributes_for :tasks, :allow_destroy => trueend
Tuesday, December 15, 2009
Nested Model Forms
<% form_for @project do |project_form| %> <div> <%= project_form.label :name, 'Project name:' %> <%= project_form.text_field :name %> </div>
<% project_form.fields_for :tasks do |task_form| %> <p> <div> <%= task_form.label :name, 'Task:' %> <%= task_form.text_field :name %> </div>
<% unless task_form.object.new_record? %> <div> <%= task_form.label :_delete, 'Remove:' %> <%= task_form.check_box :_delete %> </div> <% end %> </p> <% end %> <% end %>
<%= project_form.submit %><% end %>
Tuesday, December 15, 2009
Nested Model Forms
<% form_for @project do |project_form| %> <div> <%= project_form.label :name, 'Project name:' %> <%= project_form.text_field :name %> </div>
<% project_form.fields_for :tasks do |task_form| %> <p> <div> <%= task_form.label :name, 'Task:' %> <%= task_form.text_field :name %> </div>
<% unless task_form.object.new_record? %> <div> <%= task_form.label :_delete, 'Remove:' %> <%= task_form.check_box :_delete %> </div> <% end %> </p> <% end %> <% end %>
<%= project_form.submit %><% end %>
Tuesday, December 15, 2009
Nested Transactions
User.transaction do User.create(:username => 'Admin') User.transaction(:requires_new => true) do User.create(:username => 'Regular') raise ActiveRecord::Rollback endend
User.find(:all) # => Returns only Admin
Tuesday, December 15, 2009
Dynamic Scopes
Order.scoped_by_customer_id(12)Order.scoped_by_customer_id(12).find(:all, :conditions => "status = 'open'")Order.scoped_by_customer_id(12).scoped_by_status("open")
Tuesday, December 15, 2009
Dynamic Scopes
Order.scoped_by_customer_id(12)Order.scoped_by_customer_id(12).find(:all, :conditions => "status = 'open'")Order.scoped_by_customer_id(12).scoped_by_status("open")
Tuesday, December 15, 2009
Default Scopes
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC'endArticle.find(:all) #=> "SELECT * FROM `articles` ORDER BY created_at DESC"
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC' named_scope :published, :conditions => { :published => true }end
Article.published #=> "SELECT * FROM `articles` WHERE published = true # ORDER BY created_at DESC"
# Ignore other scoping within this blockArticle.with_exclusive_scope { find(:all) } #=> "SELECT * FROM `articles`
Tuesday, December 15, 2009
Default Scopes
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC'endArticle.find(:all) #=> "SELECT * FROM `articles` ORDER BY created_at DESC"
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC' named_scope :published, :conditions => { :published => true }end
Article.published #=> "SELECT * FROM `articles` WHERE published = true # ORDER BY created_at DESC"
# Ignore other scoping within this blockArticle.with_exclusive_scope { find(:all) } #=> "SELECT * FROM `articles`
Tuesday, December 15, 2009
Batch Processing
Article.find_each { |a| ... } # => iterate over all articles, in chunks of 1000 (the default) Article.find_each(:conditions => { :published => true }, :batch_size => 100 ) { |a| ... } # iterate over published articles in chunks of 100
Article.find_in_batches do |articles| articles.each { |a| ... } end # => articles is array of size 1000 Article.find_in_batches(batch_size => 100 ) do |articles| articles.each { |a| ... } end # iterate over all articles in chunks of 100
Article.published.find_in_batches(:batch_size => 100 ) do |articles| ...end # iterate over published articles in chunks of 100
Tuesday, December 15, 2009
Batch Processing
Article.find_each { |a| ... } # => iterate over all articles, in chunks of 1000 (the default) Article.find_each(:conditions => { :published => true }, :batch_size => 100 ) { |a| ... } # iterate over published articles in chunks of 100
Article.find_in_batches do |articles| articles.each { |a| ... } end # => articles is array of size 1000 Article.find_in_batches(batch_size => 100 ) do |articles| articles.each { |a| ... } end # iterate over all articles in chunks of 100
Article.published.find_in_batches(:batch_size => 100 ) do |articles| ...end # iterate over published articles in chunks of 100
Tuesday, December 15, 2009
Batch Processing
Article.find_each { |a| ... } # => iterate over all articles, in chunks of 1000 (the default) Article.find_each(:conditions => { :published => true }, :batch_size => 100 ) { |a| ... } # iterate over published articles in chunks of 100
Article.find_in_batches do |articles| articles.each { |a| ... } end # => articles is array of size 1000 Article.find_in_batches(batch_size => 100 ) do |articles| articles.each { |a| ... } end # iterate over all articles in chunks of 100
Article.published.find_in_batches(:batch_size => 100 ) do |articles| ...end # iterate over published articles in chunks of 100
Tuesday, December 15, 2009
HTTP Digest Authentication
class ArticlesController < ApplicationController before_filter :digest_authenticate def digest_authenticate s = authenticate_or_request_with_http_digest("Admin") do |username| (@user = User.find_by_username(username)).try(cleartext_password) end
# If authentication succeeds, log the user in. # If not, kick back out a failure # message as the response body if s session[:user_id] = @user.id else request_http_digest_authentication("Admin", "Authentication failed") end end
end
Tuesday, December 15, 2009
HTTP Digest Authentication
class ArticlesController < ApplicationController before_filter :digest_authenticate def digest_authenticate s = authenticate_or_request_with_http_digest("Admin") do |username| (@user = User.find_by_username(username)).try(cleartext_password) end
# If authentication succeeds, log the user in. # If not, kick back out a failure # message as the response body if s session[:user_id] = @user.id else request_http_digest_authentication("Admin", "Authentication failed") end end
end
Tuesday, December 15, 2009
HTTP Digest Authentication
class ArticlesController < ApplicationController before_filter :digest_authenticate def digest_authenticate s = authenticate_or_request_with_http_digest("Admin") do |username| (@user = User.find_by_username(username)).try(cleartext_password) end
# If authentication succeeds, log the user in. # If not, kick back out a failure # message as the response body if s session[:user_id] = @user.id else request_http_digest_authentication("Admin", "Authentication failed") end end
end
Tuesday, December 15, 2009
Application Templates
# template.rbrun "rm public/index.html"generate(:scaffold, "person name:string")route "map.root :controller => 'people'"rake("db:migrate")
git :initgit :add => "."git :commit => "-a -m 'Initial commit'"
> rake rails:template LOCATION=~/template.rb
Tuesday, December 15, 2009
Object#try
def remove_email(email) emails.find_by_email(email).try(:destroy) end
Tuesday, December 15, 2009
Object#try
def remove_email(email) emails.find_by_email(email).try(:destroy) end
Tuesday, December 15, 2009
XML Backends
XmlMini.backend = 'LibXML'XmlMini.backend = 'Nokogiri'
Tuesday, December 15, 2009
Plugins/Gems
Tuesday, December 15, 2009
Rack Middlewares
> script/plugin install git://github.com/ddollar/rack-debug.git
# config/environments/development.rbconfig.middleware.use "Rack::Debug"
# app/controllers/users_controller.rb...@user = User.find(params[:id])debuggerrender :show...
> rake debugConnected.
# refresh a page in your browser, your app will break at debugger statements(rdb:1) p @user#<User id: 1, name: "...">
http://github.com/rtomayko/rack-contrib/tree/master
Tuesday, December 15, 2009
Rack Middlewares
> script/plugin install git://github.com/ddollar/rack-debug.git
# config/environments/development.rbconfig.middleware.use "Rack::Debug"
# app/controllers/users_controller.rb...@user = User.find(params[:id])debuggerrender :show...
> rake debugConnected.
# refresh a page in your browser, your app will break at debugger statements(rdb:1) p @user#<User id: 1, name: "...">
http://github.com/rtomayko/rack-contrib/tree/master
Tuesday, December 15, 2009
SQL Server Adapter
> gem install dbi --version 0.4.1> gem install dbd-odbc --version 0.2.4> gem install activerecord-sqlserver-adapter
create_table :sql_server_custom_types, :force => true do |t| t.column :ten_code, :char, :limit => 10 t.column :ten_code_utf8, :nchar, :limit => 10 t.column :title_utf8, :nvarchar t.column :body, :varchar_max # varchar(max) t.column :body_utf8, :ntext t.column :body2_utf8, :nvarchar_max # nvarchar(max)end
Tuesday, December 15, 2009
• Testes (Rspec, Cucumber)
• Async (Delayed Job)
• Monitoramento (New Relic)
• Escalabilidade (Data Fabric)
• Bancos de Dados (CouchDB, Mongo)
• Life Cycle (Capistrano, Integrity, Puppet)
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009
Tuesday, December 15, 2009