Rails3 [email protected]
2010/8/17
About Me• 張文鈿 a.k.a. ihower
• http://ihower.tw
• http://twitter.com/ihower
• Rails Developer since 2006
• The Organizer of Ruby Taiwan Community
• http://ruby.tw
• http://rubyconf.tw
Agenda• Bundler
• ActiveRecord: New Query API
• ActiveRecord: New Validation API
• Views: XSS, Block Helper and JavaScript
• I18n
• New Routing API
• New ActionMailer
• Metal
1. Bundlerhttp://ihower.tw/blog/archives/4464
Gemfile # 第二個參數可以指定版本 gem "rails", "3.0.0.rc"
# 如果 require 的檔名不同,可以加上 :require gem "sqlite3-ruby", :require => "sqlite3"
# 可以用 Git 當做來源,甚至可以指定 branch, tag 或 ref。 gem 'authlogic', :git => 'git://github.com/odorcicd/authlogic.git', :branch => 'rails3'
# 可以直接用電腦裡的其他目錄 gem "rails", :path => '/Users/ihower/github/rails'
# Group 功能可以讓特定環境才會載入 group :test do gem "rspec-rails", ">= 2.0.0.beta.8" gem "webrat" end
2. AR Query API
AR queries (1)method chaining
# Rails 2users = User.find(:all, :conditions => { :name => 'ihower' }, :limit => 10, :order => 'age')
# Rails 3users = User.where(:name => 'ihower').limit(20).order('age')
AR queries (2)Unify finders, named_scope, with_scope to Relation
# Rails 2users = Userusers = users.some_named_scope if params[:some]sort = params[:sort] || "id"conditions = {}
if params[:name] conditions = User.merge_conditions( conditions, { :name => params[:name] } ) end
if params[:age] conditions = User.merge_conditions( conditions, { :age => params[:age] } )end
find_conditions = { :conditions => conditions, :order => "#{sort} #{dir}" }sort = params[:sort] || "id"
users = users.find(:all, :conditions => conditions, :order => sort )
# Rails 3users = Userusers = users.some_scope if params[:some]users = users.where( :name => params[:name] ) if params[:name]users = users.where( :age => params[:age] ) if params[:age]users = users.order( params[:sort] || "id" )
AR queries (2)Unify finders, named_scope, with_scope to Relation
# Rails 3class Product < ActiveRecord::Base scope :discontinued, where(:discontinued => true) scope :cheaper_than, lambda { |price| where("price < ?", price) }
end
# Rails 3, prefer this way moreclass Product < ActiveRecord::Base
scope :discontinued, where(:discontinued => true) def self.cheaper_than(price) where("price < ?", price) end end
AR queries (3)Using class methods instead of scopes when you need lambda
3. AR Validation API
AR validation (1)# Rails 2class User < ActiveRecord::Base validates_presence_of :email validates_uniqueness_of :email validates_format_of :email, :with => /^[\w\d]+$/ :on => :create, :message => "is invalid" end
# Rails 3class User < ActiveRecord::Base validates :email, :presence => true, :uniqueness => true, :format => { :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i } end
http://asciicasts.com/episodes/211-validations-in-rails-3
AR validation (2)custom validator
# Rails 3class User < ActiveRecord::Base validates :email, :presence => true, :uniqueness => true, :email_format => true end
class EmailFormatValidator < ActiveModel::EachValidator def validate_each(object, attribute, value) unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i object.errors[attribute] << (options[:message] || "is not formatted properly") end end end
4. Views
Secure XSSRails3 will automatically escape any string that does not
originate from inside of Rails itself
# Rails2<%=h @person.title %>
# Rails3<%[email protected] %>
# unescape string<%= @person.title.html_safe %><%= raw @person.title %>
Unobtrusive JavaScript# Rails 2link_to_remote "Name", url_path# Rails 3link_to "Name", url_path, :remote => true
# Rails 2remote_form_for @article doend# Rails 3form_for @article, :remote => true doend
You can change rails.js to jQuery version
http://ihower.tw/blog/archives/3917
# Rails 2<% form_for @article do %>end
<% content_for :sidebar do %><% end %>
# Rails 3<%= form_for @article do %>end
<%= content_for :sidebar do %><% end %>
consistent <%= %>
consistent <%= %> (2)# Rails2<% my_helper do %> blah<% end %>
# Rails2 Helperdef my_helper concat("header") yield concat("footer")end
# ordef my_helper(&block) tmp = with_output_buffer(&block) concat("header #{tmp} footer")end
# Rails3<%= my_helper do %> blah<% end %>
# Rails3 Helperdef my_helper(&block) tmp = with_output_buffer(&block) "header #{tmp} footer"end
consistent <%= %> (3)
5. I18n
{{ }} becomes to %{}
6. Routing API
Routesnice DSL
# Rails 2map.resources :people, :member => { :dashboard => :get, :resend => :post, :upload => :put } do |people| people.resource :avatraend
# Rails 3resources :people do resource :avatar member do get :dashboard post :resend put :upload endend
7. ActionMailer
ActionMailer# Rails 2class UserMailer < ActionMailer::Base
def signup(user) recipients user.email from '[email protected]' body :name => user.name subject "Signup" end
end
UserMailer.deliver_registration_confirmation(@user)
ActionMailer# Rails 3class UserMailer < ActionMailer::Base
default :from => "[email protected]" def signup(user) @name = user.name mail(:to => user.email, :subject => "Signup" ) end
end
UserMailer.registration_confirmation(@user).deliver
8. Metal
Removing Metal
• Use Rack middleware
• Use Rack endpoint in the router
• you can inherit ActionController::Metal to gain controller’s feature
Yehuda’s benchmarkrps2900 單純 Rack 極限2200 使用 config.middleware.use YourMiddleware2000 經過 Rails Route 之後1900 使用 ActionController::Metal 的最快速度1070 使用 ActionController::Base 的最快速度825 使用 ActionController::Base 加上 render :text765 使用 ActionController::Base 加上 render :template375 使用 ActionController::Base 加上 Template 跟 Layout
Thanks.More on http://ihower.tw/blog/archives/4590
andhttp://ihower.tw/rails3/