Beautiful Code in Rails 3
         by
 Gregg Pollack


Starting a new app
New Router API
ActionController - respond_with
A...
Starting a New App
$ rails
Usage:
  rails APP_PATH [options]

Options:
  ‐O, [‐‐skip‐activerecord]  # Skip ActiveRecord fi...
$ rails test_app
      create                      $ ls script/
      create  README
      create  .gitignore
            ...
old scripts   new hotness

script/generate        rails g



script/console         rails c



 script/server         rail...
old scripts   new hotness

script/generate           r g



script/console            r c



 script/server            r s...
New Router API
New Routing API



config/routes.rb
   TestApp::Application.routes.draw do |map|

      map.resources :posts

   end
New Routing API



config/routes.rb
   TestApp::Application.routes.draw do |map|

     resources :posts

   end
New Routing API
                        Rails 2
map.resources :posts do |post|
  post.resources :comments
end




        ...
New Routing API
                                                                                      Rails 2
map.resource...
Rails 2
map.connect 'login', :controller => 'session', :action => 'new'




                      Rails 3
match 'login' =>...
New Routing API
                            Rails 2
map.root :controller => "users"




                    Rails 3
root :...
For more information
             http://guides.rails.info/routing.html
Beautiful Code in Rails 3


Starting a new app
New Router API
ActionController - respond_with
ActionMailer Syntax
ActiveRe...
New ActionController Syntax
Regular Syntax
 class UsersController < ApplicationController

  def index
    @users = User.a...
New ActionController Syntax
Improved Syntax
 class UsersController < ApplicationController
   respond_to :html, :xml, :jso...
Mikel L indsaar
                  ActionMailer
New ActionMailer Syntax


                                           Rails 2
$script/generate mailer UserMailer welcome fo...
New ActionMailer Syntax

                                           Rails 2
def welcome(user, subdomain)
  subject 'Welcom...
New ActionMailer Syntax

                                                                  Rails 3
class UserMailer < Acti...
Nic k Kallen
               ActiveRelation




                replaces the internal ad-hoc query generation with
        ...
ActiveRelation
                                          Rails 2
@posts = Post.find(:all, :conditions => {:published => tr...
ActiveRelation


@posts = Post.where(:published => true)

if params[:order]
  @posts = @posts.order(params[:order])
end

@...
We can refactor!
@posts = Post.where(:published => true)

if params[:order]
  @posts = @posts.order(params[:order])
end


...
ActiveRelations can be Shared
@posts = Post.where(:published => true).order(params[:order])



posts = Post.order(params[:...
ActiveRelation
@published = Post.published
@unpublished = Post.unpublished

                                              ...
ActiveRelation
    New Finder Methods
where(:conditions)
having(:conditions)
select
group
order
limit
offset
joins
include...
ActiveRelation


                                                        Rails 2
Post.find(:all, :conditions => {:author =...
Beautiful Code in Rails 3


Starting a new app
New Router API
ActionController - respond_with
ActionMailer Syntax
ActiveRe...
Use of external libraries



    ActiveRecord                            ActiveRelation



      ActionView               ...
Cross-Site Scripting (XSS)




            Rails 2                         Rails 2
<%= @post.body %>                <%= h ...
Adopting Unobtrusive Javascript

HTML 5 custom data attributes                                   data-*
Custom data attrib...
Adopting Unobtrusive Javascript

                                        Rails 2
<%= link_to_remote 'Show', :url => post %...
Adopting Unobtrusive Javascript

                                    Rails 2
 <% remote_form_for(@post) do |f| %>


      ...
Adopting Unobtrusive Javascript

                                  Rails 2        Rails 3
 <%= link_to 'Destroy', post, :m...
Adopting Unobtrusive Javascript

                                                                             Rails 2 Rail...
Adopting Unobtrusive Javascript

                                                                       Rails 2
  <%= f.su...
Adopting Unobtrusive Javascript


HTML 5 custom data attributes

  data-remote



  data-method



  data-confirm



  dat...
/public/stylesheets/rails.js
document.observe("dom:loaded", function() {

  $(document.body).observe("click", function(eve...
jQuery in Rails?
http://github.com/rails/jquery-ujs




 $('a[data-confirm],input[data-confirm]').live('click', function (...
Deprecated Methods
   link_to_remote
   remote_form_for
   observe_field
   observe_form
   form_remote_tag
   button_to_r...
Beautiful Code in Rails 3


Starting a new app
New Router API
ActionController - respond_with
ActionMailer Syntax
ActiveRe...
Missing (that I didn’t have time for)
                            APIs

                                  Bundler
   http:...
Creative Commons
            name                     author                                URL
rainbow of 80s toys       ...
Presentation by:         If you need help with a Rails 3
                            project, feel free to give us a call
...
Upcoming SlideShare
Loading in...5
×

Rails 3 Beautiful Code

98,962

Published on

On February 18th, 2010 was O'Reilly's "Exploring Rails 3" online conference and these are Gregg Pollack's slides. They are by no means a complete record of improvements in Rails 3, but they should serve to get your appetite wet.

Published in: Technology
23 Comments
217 Likes
Statistics
Notes
No Downloads
Views
Total Views
98,962
On Slideshare
0
From Embeds
0
Number of Embeds
18
Actions
Shares
0
Downloads
2,645
Comments
23
Likes
217
Embeds 0
No embeds

No notes for slide

Rails 3 Beautiful Code

  1. 1. Beautiful Code in Rails 3 by Gregg Pollack Starting a new app New Router API ActionController - respond_with ActionMailer Syntax ActiveRelation (arel) ERB Strings Escaped Unobtrusive Javascript
  2. 2. Starting a New App $ rails Usage:   rails APP_PATH [options] Options: ‐O, [‐‐skip‐activerecord]  # Skip ActiveRecord files   ‐r, [‐‐ruby=PATH]          # Path to the Ruby binary of your choice                              # Default: /Users/greggpollack/.rvm/rubies/ruby‐   ‐T, [‐‐skip‐testunit]      # Skip TestUnit files       [‐‐dev]                # Setup the application with Gemfile pointing                                to your rails checkout ‐J, [‐‐skip‐prototype]     # Skip Prototype files   ‐G, [‐‐skip‐git]           # Skip Git ignores and keeps   ‐m, [‐‐template=TEMPLATE]  # Path to an application template    ‐d, [‐‐database=DATABASE]  # Preconfigure for selected database        [‐‐edge]               # Setup the application with Gemfile                              # pointing to Rails repository  
  3. 3. $ rails test_app       create   $ ls script/       create  README       create  .gitignore          ... $ cd test_app/   rails $ rails Usage: rails COMMAND [ARGS] The most common rails commands are:  generate    Generate new code (short‐cut alias: "g") c console     Start the Rails console (short‐cut alias: " ") s server      Start the Rails server (short‐cut alias: " ") dbconsole   Start a console for the database specified in config/database.yml             (short‐cut alias: "db") In addition to those, there are:  application  Generate the Rails application code  destroy      Undo code generated with "generate"  benchmarker  See how fast a piece of code runs  profiler     Get profile information from a piece of code  plugin       Install a plugin  runner       Run a piece of code in the application environment All commands can be run with ‐h for more information.
  4. 4. old scripts new hotness script/generate rails g script/console rails c script/server rails s script/dbconsole rails db
  5. 5. old scripts new hotness script/generate r g script/console r c script/server r s script/dbconsole r db alias r='rails'
  6. 6. New Router API
  7. 7. New Routing API config/routes.rb TestApp::Application.routes.draw do |map| map.resources :posts end
  8. 8. New Routing API config/routes.rb TestApp::Application.routes.draw do |map| resources :posts end
  9. 9. New Routing API Rails 2 map.resources :posts do |post| post.resources :comments end Rails 3 resources :posts do resources :comments end
  10. 10. New Routing API Rails 2 map.resources :posts, :member => { :confirm => :post, :notify => :post } do |post| post.resources :comments, :member => { :preview => :post }, :collection => { :archived => :get } end Rails 3 resources :posts do member do Rails 3 post :confirm resources :posts do get :notify member do end post :confirm get :notify resources :comments do end member do post :preview resources :comments do end post :preview, :on => :member get :archived, :on => :collection collection do end get :archived end end end end
  11. 11. Rails 2 map.connect 'login', :controller => 'session', :action => 'new' Rails 3 match 'login' => 'session#new' Named Route login_path Rails 2 map.login 'login', :controller => 'session', :action => 'new' Rails 3 match 'login' => 'session#new', :as => :login
  12. 12. New Routing API Rails 2 map.root :controller => "users" Rails 3 root :to => "users#index" Legacy Route Rails 2 map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' Rails 3 match ':controller(/:action(/:id(.:format)))' (commented out by default)
  13. 13. For more information http://guides.rails.info/routing.html
  14. 14. Beautiful Code in Rails 3 Starting a new app New Router API ActionController - respond_with ActionMailer Syntax ActiveRelation (arel) ERB Strings Escaped Unobtrusive Javascript #Rails3OMGPonies!
  15. 15. New ActionController Syntax Regular Syntax class UsersController < ApplicationController def index @users = User.all respond_to do |format| format.html format.xml { render :xml => @users.to_xml } end end def show @user = User.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @user } end end ...
  16. 16. New ActionController Syntax Improved Syntax class UsersController < ApplicationController respond_to :html, :xml, :json def index @users = User.all respond_with(@users) end def show @user = User.find(params[:id]) respond_with(@user) end ...
  17. 17. Mikel L indsaar ActionMailer
  18. 18. New ActionMailer Syntax Rails 2 $script/generate mailer UserMailer welcome forgot_password create  app/models/user_mailer.rb Rails 3 $r g mailer UserMailer welcome forgot_password create  app/mailers/user_mailer.rb
  19. 19. New ActionMailer Syntax Rails 2 def welcome(user, subdomain) subject 'Welcome to TestApp' recipients user.email from 'admin@testapp.com' body :user => user, :subdomain => subdomain end UserMailer.deliver_welcome(user, subdomain) Rails 3 def welcome(user, subdomain) @user = user @subdomain = subdomain mail(:from => "admin@testapp.com", :to => user.email, :subject => "Welcome to TestApp") end UserMailer.welcome(user, subdomain).deliver
  20. 20. New ActionMailer Syntax Rails 3 class UserMailer < ActionMailer::Base default :from => "admin@testapp.com" def welcome(user, subdomain) @user = user @subdomain = subdomain attachments['test.pdf'] = File.read("#{Rails.root}/public/test.pdf") mail(:to => @user.email, :subject => "Welcome to TestApp") do |format| format.html { render 'other_html_welcome' } format.text { render 'other_text_welcome' } end end end welcome.text.erb Defaults welcome.html.erb
  21. 21. Nic k Kallen ActiveRelation replaces the internal ad-hoc query generation with query generation based on relational algebra.
  22. 22. ActiveRelation Rails 2 @posts = Post.find(:all, :conditions => {:published => true}) immediately queries the db returns an Array of Posts Rails 3 @posts = Post.where(:published => true) doesn’t query the db returns an ActiveRecord::Relation
  23. 23. ActiveRelation @posts = Post.where(:published => true) if params[:order] @posts = @posts.order(params[:order]) end @posts.each do |p| ... Que end ry r uns here Lazy Loading
  24. 24. We can refactor! @posts = Post.where(:published => true) if params[:order] @posts = @posts.order(params[:order]) end @posts = Post.where(:published => true) @posts = @posts.order(params[:order]) @posts = Post.where(:published => true).order(params[:order])
  25. 25. ActiveRelations can be Shared @posts = Post.where(:published => true).order(params[:order]) posts = Post.order(params[:order]) @published = posts.where(:published => true) @unpublished = posts.where(:published => false) This is obviously a bad example (should be using named routes) @published = Post.published @unpublished = Post.unpublished
  26. 26. ActiveRelation @published = Post.published @unpublished = Post.unpublished Rails 2 class Post < ActiveRecord::Base default_scope :order => 'title' named_scope :published, :conditions => {:published => true} named_scope :unpublished, :conditions => {:published => false} end Rails 3 class Post < ActiveRecord::Base default_scope order('title') scope :published, where(:published => true) scope :unpublished, where(:published => false) end
  27. 27. ActiveRelation New Finder Methods where(:conditions) having(:conditions) select group order limit offset joins includes(:include) lock readonly from
  28. 28. ActiveRelation Rails 2 Post.find(:all, :conditions => {:author => "Joe"}, :includes => :comments, :order => "title", :limit => 10) Rails 3 Post.where(:author => "Joe").include(:comments).order(:title).limit(10) Remember, this version doesn’t do the query immediately
  29. 29. Beautiful Code in Rails 3 Starting a new app New Router API ActionController - respond_with ActionMailer Syntax ActiveRelation (arel) ERB Strings Escaped Unobtrusive Javascript #Rails3OMGPonies!
  30. 30. Use of external libraries ActiveRecord ActiveRelation ActionView Erubis Erubis is a fast, secure, and very extensible implementation of ERB
  31. 31. Cross-Site Scripting (XSS) Rails 2 Rails 2 <%= @post.body %> <%= h @post.body %> (unsafe) (safe) Rails 3 Rails 3 <%= raw @post.body %> <%= @post.body %> (unsafe) (safe)
  32. 32. Adopting Unobtrusive Javascript HTML 5 custom data attributes data-* Custom data attributes are intended to store custom data private to the page or application, for which there are no more appropriate attributes or elements data-remote data-method data-confirm data-disable-with
  33. 33. Adopting Unobtrusive Javascript Rails 2 <%= link_to_remote 'Show', :url => post %> <a href="#" onclick="new Ajax.Request('/posts/1', {asynchronous:true, evalScripts:true, parameters:'authenticity_token=' + encodeURIComponent('9sk..44d')}); return false;">Show</a> Rails 3 <%= link_to 'Show', post, :remote => true %> <a href="/posts/1" data-remote="true">Show</a>
  34. 34. Adopting Unobtrusive Javascript Rails 2 <% remote_form_for(@post) do |f| %> <form action="/posts" class="new_post" id="new_post" method="post" onsubmit="new Ajax.Request('/posts', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;"> Rails 3 <% form_for(@post, :remote => true) do |f| %> <form action="/posts" class="new_post" data-remote="true" id="new_post" method="post">
  35. 35. Adopting Unobtrusive Javascript Rails 2 Rails 3 <%= link_to 'Destroy', post, :method => :delete %> <a href="/posts/1" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '9skdJ0k+l9/q3PWToz6MtfyiB2gcyhnKubeGV6WFL44='); f.appendChild(s);f.submit();return false;">Destroy</a> <a href="/posts/1" data-method="delete" rel="nofollow">Destroy</a>
  36. 36. Adopting Unobtrusive Javascript Rails 2 Rails 3 <%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %> <a href="/posts/1" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '9skdJ0k+l9/q3PWToz6MtfyiB2gcyhnKubeGV6WFL44='); f.appendChild(s);f.submit(); };return false;">Destroy</a> <a href="/posts/1" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a>
  37. 37. Adopting Unobtrusive Javascript Rails 2 <%= f.submit 'Create Post', :disable_with => "Please wait..." %> <input id="post_submit" name="commit" onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Please wait...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Create Post" /> Rails 3 <%= f.submit :disable_with => "Please wait..." %> <input data-disable-with="Please wait..." id="post_submit" name="commit" type="submit" value="Create Post" /> Notice, the button label has an intellegent default
  38. 38. Adopting Unobtrusive Javascript HTML 5 custom data attributes data-remote data-method data-confirm data-disable-with
  39. 39. /public/stylesheets/rails.js document.observe("dom:loaded", function() { $(document.body).observe("click", function(event) { var message = event.element().readAttribute('data-confirm'); if (message) { // ... Do a confirm box } var element = event.findElement("a[data-remote=true]"); if (element) { // ... Do the AJAX call } var element = event.findElement("a[data-method]"); if (element) { // ... Create a form } });
  40. 40. jQuery in Rails? http://github.com/rails/jquery-ujs $('a[data-confirm],input[data-confirm]').live('click', function () { // ... Do a confirm box }); $('form[data-remote="true"]').live('submit', function (e) { // ... Do an AJAX call });
  41. 41. Deprecated Methods link_to_remote remote_form_for observe_field observe_form form_remote_tag button_to_remote submit_to_remote link_to_function periodically_call_remote prototype_legacy_helper http://github.com/rails/prototype_legacy_helper
  42. 42. Beautiful Code in Rails 3 Starting a new app New Router API ActionController - respond_with ActionMailer Syntax ActiveRelation (arel) ERB Strings Escaped Unobtrusive Javascript #Rails3OMGPonies!
  43. 43. Missing (that I didn’t have time for) APIs Bundler http://railscasts.com/episodes/201-bundler Making Generators with Thor http://bit.ly/rails3generators
  44. 44. Creative Commons name author URL rainbow of 80s toys merwing✿little dear http://www.flickr.com/photos/merwing/2152164258/ Old Loc Merlijn Hoek http://www.flickr.com/photos/merlijnhoek/1040997599/ Notting Hill Gate Eole http://www.flickr.com/photos/eole/942309733/ Britomart Train Station EssjayNZ http://www.flickr.com/photos/essjay/260511465/ Das Licht Small http://www.flickr.com/photos/small/62713023/ Metro Genova opti mystic http://www.flickr.com/photos/miiilio/2503634282/ Immobility Dilemna gilderic http://www.flickr.com/photos/gilderic/3528157964/ train station nolifebeforecoffee http://www.flickr.com/photos/nolifebeforecoffee/1803584805/ Mystical station Jsome1 http://www.flickr.com/photos/jsome1/2226394415/ Railswaystation Pieter Musterd http://www.flickr.com/photos/piet_musterd/2233025691/ The Handover MarkyBon http://www.flickr.com/photos/markybon/152769885/ EN57 magro_kr http://www.flickr.com/photos/iks_berto/1328682171/
  45. 45. Presentation by: If you need help with a Rails 3 project, feel free to give us a call http://envylabs.com Come to our Rails 3 training at Railsconf 2010 Gregg Pollack http://bit.ly/rails3ropes 407-754-5517 Gregg@EnvyLabs.com We’re also available to run Rails 3 Training at your company, email: Ruby5 Podcast Gregg@EnvyLabs.com http://ruby5.envylabs.com
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×