What's new in Rails 2?

Post on 12-Sep-2014

30.147 views 3 download

Tags:

description

An overview of the major new features and changes in Rails 2.0. Originally presented on December 11th, 2007 at NYC.rb.

Transcript of What's new in Rails 2?

What’s new in Rails 2?Bryan Helmkamp

http://brynary.com/

“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/