what's new in rails 2?
Post on 12-Sep-2014
30.146 views
DESCRIPTION
An overview of the major new features and changes in Rails 2.0. Originally presented on December 11th, 2007 at NYC.rb.TRANSCRIPT
“Look at all the things I’m NOT
doing.”–DHH during the “Creating a blog
in 15 minutes” screencast
Evolutionary, not revolutionary.
ActiveRecord
Numerical validation
•Gains the ability to specify comparisons.
•Examples:validates_numericality_of :salary, :greater_than => 49_000
validates_numericality_of :age, :less_than_or_equal => 99
validates_numericality_of :employees, :greater_than => 0
:allow_blank => true
Skips validation for empty strings and nil.
XML in, JSON out>> Post.new.from_xml({:title => "Hello!", :body => "text"}.to_xml)
=> #<Post id: nil, title: "Hello!", body: "text", created_at: nil, updated_at: nil>
>> Post.new(:title => "Hello!", :body => "text").to_json
=> "{"updated_at": null, "title": "Hello!", "body": "text", "created_at": null}"
Sexy migrations
create_table :posts do |t|
t.belongs_to :blog, :null => false
t.string :title, :subtitle
t.text :body
t.timestamps
end
Query cache•Very dumb. Checks SQL string
equality.
•Cleared by any INSERT/UPDATE/DELETE.
•Enabled per-action by default.
•Can be skipped if necessary:def self.uncached_newest uncached do find(:all, :order => :created_at) endend
Foxy Fixtures
Three main features
•Don’t specify the IDs for each record.
•Reference associated fixtures by name.
•Sets created_at and updated_at to Time.now automatically.
Foxy Fixtures example
# blogs.ymlmy_blog: name: "My awesome blog"
# posts.ymlfirst_post: blog: my_blog title: "First post!"
fixtures :allLoad all fixtures for all test cases.
(Recommended!)
ActionPack
Cookie sessions•Now the default session store.
•Stored in clear text, secured with a hash.
•Configure a secret in environment.rb:
Rails::Initializer.run do |config| config.action_controller.session = { :session_key => '_rails_app_session', :secret => 'e96a9......aef9111a' }end
HTTP-only cookiesPrevents access to cookies from JavaScript.
CSRF protection
•Enabled by default in application.rb
•Uses a token to verify requests are from the application, not a malicious site.
•Built-in to form_tag and friends.
Partial layoutsUse with partials:<% render :partial => "post", :layout => "window" %>
or with a block:<% render :layout => "window", :locals => { :name => "Recent" } do %>
<% for post in @recent_posts %>
<h2><%=h post.title %></h2>
<!-- ... -->
<% end %>
<% end %>
Route namespaces
map.namespace :admin do |admin| # Maps to Admin::PostsController admin.resources :postsend# Maps to PostsControllermap.resources :posts
Semicolon is dead.Long live forward
slash!
Association routing shortcuts
map.resources :blogs, :has_many => [:posts, :themes], :has_one => :owner
HTTP authentication
class PostsController < ApplicationController
USER_NAME, PASSWORD = "bryan", "secret"
before_filter :authenticate, :except => [ :index ]
...
private
def authenticate
authenticate_or_request_with_http_basic do |user_name, password|
user_name == USER_NAME && password == PASSWORD
end
end
end
Exception handlersclass ApplicationController < ActionController::Base
rescue_from User::NotAuthorized, :with => :deny_access
rescue_from 'MyAppError::Base' do |exception|
render :xml => exception.to_xml, :status => 500
end
protected
def deny_access
# ...
end
end
Asset caching
•Concatenates file contents.
•Only active in production mode.
•Examples:<%= stylesheet_link_tag "reset", "main", :cache => true %>
<%# Cache in public/javascripts/special.js %>
<%= javascript_include_tag "whiz", "bang", :cache => "special" %>
Asset servers
•Distributes request to four asset hosts.
•Speeds up page load time considerably.
•In production.rb:ActionController::Base.asset_host = "asset
%d.example.com"
AtomFeedHelper# index.atom.builder:
atom_feed do |feed|
feed.title("Bryan's Bytes")
feed.updated((@posts.first.created_at))
for post in @posts
feed.entry(post) do |entry|
entry.title(post.title)
entry.content(post.body, :type => 'html')
entry.author do |author|
author.name("NYC.rb")
end
end
end
end
Multiview
•Template filename changes:
filename.format.renderer
•Examples:
show.csv.erb
edit.html.haml
index.atom.builder
simply_helpfulNow in core... but you should’ve been using it
already.
dom_class and dom_id
•dom_class(@person) => "person"
•dom_class(Person) => "person"
•dom_class(@person, :edit) => "edit_person"
•dom_id(@person) => "person_1234"
•dom_id(Person.new) => "new_person"
div_for/content_tag_for<% div_for @person do %> <!-- ... --><% end %>
<!-- Becomes --><div class="person" id="person_42"> <!-- ... --></div>
url_for for models
•url_for(@post) works like post_path(@post).
•url_for(Post.new) works like new_post_path.
•Works with link_to, redirect_to, etc.
render :partial for AR
• render :partial => @post works like render :partial => "post", :object => @post
• render :partial => @posts works like render :partial => "post", :collection => @posts
form_for•Determines form action based on
the record. (e.g. post_path or new_post_path)
•New records use :method => :post
•Existing records use :method => :put
•Automatically adds a HTML class and ID
form_for example
<% form_for @person do |f| %>
<%= f.text_field :name %>
<% end %>
<!-- Becomes -->
<form action="/people" method="post" class="person" id="new_person">
<input type="text" name="person[name]" id="person_name" />
</form>
Extra Goodies
Debugging
Getting started
•sudo gem install -y ruby-debug
•Call the method “debugger” in your code
•script/server --debugger
Debugger commands
• irb – Drop into an irb session
• list – List the code surround the breakpoint
•p/pp – Print results of an expression
•up – Move one frame higher
• cont – Resume execution
•next/step – Execute one line at a time.
•where – Display the current stack
Live demo
assert_emails
# Assert one email is sent during actionassert_emails 1 do post :signup, :name => "Bryan"end
# Assert no emails are sentpost :signup, :name => ""assert_no_emails
Hash filtering
•Hash#except is the inverse of Hash#slice.
•Example:
>> {:foo => 1, :bar => 2}.except(:bar, :baz)
=> {:foo=>1}
Database Rake tasks
•rake db:create and db:create:all
•rake db:drop and db:drop:all
•rake db:reset
•rake db:rollback (defaults to STEP=1)
•rake db:version
List routes with Rake
$ rake routes
posts GET /posts {:controller=>"posts", :action=>"index"}
formatted_posts GET /posts.:format {:controller=>"posts", :action=>"index"}
POST /posts {:controller=>"posts", :action=>"create"}
POST /posts.:format {:controller=>"posts", :action=>"create"}
new_post GET /posts/new {:controller=>"posts", :action=>"new"}
formatted_new_post GET /posts/new.:format {:controller=>"posts", :action=>"new"}
edit_post GET /posts/:id/edit {:controller=>"posts", :action=>"edit"}
formatted_edit_post GET /posts/:id/edit.:format {:controller=>"posts", :action=>"edit"}
post GET /posts/:id {:controller=>"posts", :action=>"show"}
formatted_post GET /posts/:id.:format {:controller=>"posts", :action=>"show"}
PUT /posts/:id {:controller=>"posts", :action=>"update"}
PUT /posts/:id.:format {:controller=>"posts", :action=>"update"}
DELETE /posts/:id {:controller=>"posts", :action=>"destroy"}
DELETE /posts/:id.:format {:controller=>"posts", :action=>"destroy"}
/:controller/:action/:id
/:controller/:action/:id.:format
Initializer hooks
Rails load order:
1.config/preinitializer.rb
2.config/environment.rb
3.config/environments/RAILS_ENV.rb
4.config/initializers/*.rb
Code annotations
Finds FIXME, TODO and OPTIMIZE comments.
$ rake notesapp/models/post.rb: * [ 2] [TODO] : Add support for themes
app/views/layouts/application.rhtml: * [ 1] [FIXME] Will break with less than three posts
Request profiler
•sudo gem install -y ruby-prof
•Example:$ cat login_session.rb
get_with_redirect '/'
post_with_redirect '/sessions', :password => 'NYC.rb!'
$ ./script/performance/request -n 10 login_session.rb
Losing weight
ActionWebService is out.Use ActiveResource for
REST.
acts_as_* behaviors
script/plugin install http://svn.rubyonrails.org/rails/plugins/acts_as_list/
script/plugin install
http://svn.rubyonrails.org/rails/plugins/acts_as_nested_set/
script/plugin install
http://svn.rubyonrails.org/rails/plugins/acts_as_tree/
Controller variables
•Don’t use @params, @session, @flash, @request or @env.
•Just drop the “@” and use the methods.
ActiveRecord finders
•Post.find_all becomes Post.find(:all).
•Post.find_first becomes Post.find(:first).
Components
•Interesting feature, but too slow.
•Try refactoring to partials and filters...
•...or grab Sebastian Delmont’s plugin:
http://dev.notso.net/svn/rails/plugins/embedded_actions/trunk/
Renamed routes
•Nested resources now use the parent name as a prefix.
•Example:map.resources :blogs do |blog| blog.resources :postsend•post_path becomes blog_post_path, etc.
Pagination
Switch to will_paginate (recommended).
http://errtheblog.com/posts/56-im-paginating-again
Or install the classic_pagination plugin:
script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination
Database adapters
Adapters except SQLite, MySQL and PostgreSQL were removed from Rails core.
sudo gem install activerecord-oracle-adapter
Form helpers
•start_form_tag and end_form_tag are gone.
•Switch to the form_tag block syntax.
•Use form_for when possible.
form_tag example
<%= start_form_tag posts_path %> <%= text_field :post, :title %><%= end_form_tag %>
becomes <% form_tag posts_path do %> <%= text_field :post, :title %> <% end %>
AJAX view helpers
Autocomplete and in-place editing moved to plugins.script/plugin install http://svn.rubyonrails.org/rails/plugins/auto_complete/
script/plugin install http://svn.rubyonrails.org/rails/plugins/in_place_editing/
“Use the Source, Luke.”
How to upgrade1.Upgrade to Rails 1.2.6.
2.Eliminate deprecation warnings.
3.Make sure all your tests pass.
4.Upgrade to Rails 2.0.1.
5.Run Mislav’s Rails 2 compatibility checker script. (http://pastie.caboo.se/private/krcevozww61drdeza13e3a)
6.Make sure all your tests pass.
Questions?What’s new in
Rails 2?Bryan Helmkamp
http://brynary.com/
Photos used• http://www.flickr.com/photos/kaufman/81616562/
• http://icanhascheezburger.com/2007/01/12/wait-ill-fix-it/