Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What to expect in Rails 4.0

What to expect in Rails 4.0

The 4.0 release of Ruby on Rails is right around the corner. I'm going to highlight some of the new features and changes in the newest version of Rails, as well as features that will be removed or deprecated in Rails core.

(Note: The content of this slide may not reflect the final version of the release.)

Presented at BostonRB on September 11, 2012. Video is available at http://bostonrb.org/presentations/what-to-expect-in-rails-40.

Prem Sichanugrist

September 11, 2012
Tweet

More Decks by Prem Sichanugrist

Other Decks in Programming

Transcript

  1. 4.0

  2. New Features Strong Parameters Null Relation Rails Queue Russian Doll

    Caching Relation#inspect Schema Cache Dump Routing Concern HTML5 tag helpers HTTP PATCH {asset}_url helpers .first and .last now have order() defined Scope mutation config.eager_load replaces threadsafe! Relation#pluck takes multiple arguments
  3. Strong Parameters • Replaces attr_accessor and attr_protected • Will be

    extracted as a gem (Dependency of Rails 4.0) • Moves parameters filtering concern to controller
  4. # app/models/user.rb class User < ActiveRecord::Base attr_accessible :username, :password, :password_confirmation

    end # app/controllers/users_controller.rb class UsersController < ApplicationController def create @user = User.create!(params[:user]) redirect_to @user end end
  5. # app/models/user.rb class User < ActiveRecord::Base; end # app/controllers/users_controller.rb class

    UsersController < ApplicationController def create @user = User.create!(user_params) redirect_to @user end private def user_params params.require(:user).permit(:username, :password, :password_confirmation) end end
  6. # app/controllers/users_controller.rb class UsersController < ApplicationController def create @user =

    User.create!(params[:user]) redirect_to @user end end #=> Raises ActiveModel::ForbiddenAttributes
  7. Easier multi-roles filtering # app/controllers/users_controller.rb class UsersController < ApplicationController def

    user_params params.require(:user).permit(:username, :password, :password_confirmation) end end # app/controllers/admin/users_controller.rb class Admin::UsersController < ApplicationController def user_params params.require(:user).permit(User.attribute_names) end end
  8. Job # Requires an object that respond to #run class

    UserRegistrationMailerJob < Struct.new(:user_id) def run user = User.find(user_id) UserMailer.welcome_email(user).deliver end end
  9. Queue it! # Pass in an object that respond to

    #run class UserRegistrationMailerJob < Struct.new(:user_id) def run user = User.find(user_id) UserMailer.welcome_email(user).deliver end end # Usage Rails.queue.push UserRegistrationMailerJob(@user.id)
  10. Configurations # Default Container and Consumer config.queue = :asynchronous config.queue

    = :synchronous # Resque support in Resque 2.0.0.beta config.queue = :resque
  11. <%# app/views/topics/show.html.erb %> <% cache [ "v1", @topic ] do

    %> <h1><%= Topic.title %></h1> <%= render @topic.posts %> <% end %> <%# app/views/posts/_post.html.erb %> <% cache [ "v1", post ] do %> <%= render post.author %> <%= post.content %> <% end %> <%# app/views/users/_user.html.erb %> <% cache [ "v1", user ] do %> Posted by <%= user.name %> <% end %> Russian Doll Caching
  12. <%# app/views/topics/show.html.erb %> <% cache [ "v2", @topic ] do

    %> ... <% end %> <%# app/views/posts/_post.html.erb %> <% cache [ "v1", post ] do %> ... <% end %> <%# app/views/users/_user.html.erb %> <% cache [ "v1", user ] do %> ... <% end %> Expire Cache
  13. Expire Cache <%# app/views/topics/show.html.erb %> <% cache [ "v3", @topic

    ] do %> ... <% end %> <%# app/views/posts/_post.html.erb %> <% cache [ "v2", post ] do %> ... <% end %> <%# app/views/users/_user.html.erb %> <% cache [ "v1", user ] do %> ... <% end %>
  14. Expire Cache <%# app/views/topics/show.html.erb %> <% cache [ "v4", @topic

    ] do %> ... <% end %> <%# app/views/posts/_post.html.erb %> <% cache [ "v3", post ] do %> ... <% end %> <%# app/views/users/_user.html.erb %> <% cache [ "v2", user ] do %> ... <% end %>
  15. <%# app/views/topics/show.html.erb %> <% cache @topic do %> <h1><%= Topic.title

    %></h1> <%= render @topic.posts %> <% end %> <%# app/views/posts/_post.html.erb %> <% cache post do %> <%= render post.author %> <%= post.content %> <% end %> <%# app/views/users/_user.html.erb %> <% cache user do %> Posted by <%= user.name %> <% end %> Your Template
  16. Generate MD5 of template and its dependencies as cache key

    views/topics/605816632-20120810191209/d9fb66b120b61f46707c67ab41d93cb2
  17. $ rake cache_digests:dependencies TEMPLATE=topics/show [ "posts/post" ] $ rake cache_digests:nested_dependencies

    TEMPLATE=topics/show [ { "posts/post": [ "users/user" ] } ] Inspect Dependencies
  18. $ bundle exec rake db:schema:cache:dump => generate db/schema_cache.dump # You

    might want to add this to your repository $ RAILS_ENV=production bundle exec rails server => use db/schema_cache.dump
  19. RFC 5789 • The PUT method is already defined to

    overwrite a resource with a complete new body, and cannot be reused to do partial changes. Otherwise, proxies and caches, and even clients and servers, may get confused as to the result of the operation. • This specification defines the new HTTP/1.1 method, PATCH, which is used to apply partial modifications to a resource.
  20. <%= form_for @user do |f| %> <form action="/users/1" method="post" ...

    > <div style="margin:0;padding:0;display:inline"> <input name="utf8" type="hidden" value="&#x2713;" /> <input name="_method" type="hidden" value="patch" /> <input name="authenticity_token" ... /> ...
  21. Before resources :messages do resources :comments end resources :posts do

    resources :comments resources :images, only: :index end
  22. After concern :commentable do resources :comments end concern :image_attachables do

    resources :images, only: :index end resources :messages, concerns: :commentable resources :posts, concerns: [:commentable, : image_attachables]
  23. Relation.first Relation.last # User.first SELECT “users”.* FROM “users” ORDER BY

    id LIMIT 1 # User.last SELECT “users”.* FROM “users” ORDER BY id DESC LIMIT 1
  24. # app/controllers/users_controller.rb class UsersController < ApplicationController def index @users =

    Users.name_starts_with(params[:prefix]). order(:name).paginate(params[:page], :per_page => 15) end end # app/models/user.rb class User < ActiveRecord::Base def self.starts_with(prefix) if prefix.present? where('name LIKE ?', "#{prefix}%") else # ... ? ... end end end
  25. # app/controllers/users_controller.rb class UsersController < ApplicationController def index @users =

    Users.name_starts_with(params[:prefix]). order(:name).paginate(params[:page], :per_page => 15) end end # app/models/user.rb class User < ActiveRecord::Base def self.starts_with(prefix) if prefix.present? where('name LIKE ?', "#{prefix}%") else [] end end end
  26. # app/controllers/users_controller.rb class UsersController < ApplicationController def index @users =

    Users.name_starts_with(params[:prefix]). order(:name).paginate(params[:page], :per_page => 15) end end # app/models/user.rb class User < ActiveRecord::Base def self.starts_with(prefix) if prefix.present? where('name LIKE ?', "#{prefix}%") else [] #=> NoMethodError when calling #order end end end
  27. # app/controllers/users_controller.rb class UsersController < ApplicationController def index @users =

    Users.name_starts_with(params[:prefix]). order(:name).paginate(params[:page], :per_page => 15) end end # app/models/user.rb class User < ActiveRecord::Base def self.starts_with(prefix) if prefix.present? where('name LIKE ?', "#{prefix}%") else none end end end
  28. # app/controller/users_controller.rb class UsersController < ApplicationController def index @users =

    User @users = @users.where(:id => params[:id]) if params[:id] @users = @users.includes(:comments) if params[:comments] @users = @users.order(:name) end end
  29. # app/controller/users_controller.rb class UsersController < ApplicationController def index @users =

    User @users.where!(:id => params[:id]) if params[:id] @users.includes!(:comments) if params[:comments] @users.order!(:name) end end
  30. bind! create_with! eager_load! extending! from! group! having! includes! joins! limit!

    lock! offset! order! preload! readonly! references! reorder! reverse_order! select! uniq! where!
  31. find_all_by_... => where(...) find_last_by_... => where(...).last scoped_by_... => where(...) find_or_create_by_...

    => where(...).first_or_create find_or_create_by_...! => where(...).first_or_create! find_or_initialize_by_... => where(...).first_or_initialize
  32. Ver

  33. Try Now! # Gemfile # gem 'rails', '3.2.8' gem 'rails',

    github: 'rails/rails' $ bundle update