rails for kids 2009

Post on 11-Sep-2014

15 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Evolução do Ruby on Rails através dos anos. Dia 12/set.

TRANSCRIPT

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" <railssummit@locaweb.com.br>)

ExceptionNotifier.exception_recipients = %w(fabioakita@gmail.com fabio.akita@locaweb.com.br)

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" <railssummit@locaweb.com.br>)

ExceptionNotifier.exception_recipients = %w(fabioakita@gmail.com fabio.akita@locaweb.com.br)

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 &amp; 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 "system@example.com" 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

Obrigadofabioakita@gmail.com

Tuesday, December 15, 2009

top related