Slide 1

Slide 1 text

What to expect in Rails 4.0

Slide 2

Slide 2 text

4.0

Slide 3

Slide 3 text

Question?

Slide 4

Slide 4 text

#rails4 Tweet with this hashtag

Slide 5

Slide 5 text

Stats

Slide 6

Slide 6 text

5,863 Commits 62,684 + 64,585 –

Slide 7

Slide 7 text

$ git log 9d6e52b...master |\ pipe> sort | uniq | wc -l 683 683 Contributors

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Deprecations ActiveRecord::SessionStore Old Dynamic Finders ActiveResource .scoped() Old Hash Finders Eager Evaluated Scope Rails Plugins

Slide 10

Slide 10 text

Release Note http://edgeguides.rubyonrails.org/4_0_release_notes.html

Slide 11

Slide 11 text

Notable Changes

Slide 12

Slide 12 text

Strong Parameters

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

# 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

Slide 15

Slide 15 text

# 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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

params.require(:user).permit(:username, :password, :password_confirmation)

Slide 19

Slide 19 text

params.require(:user).permit(:username, :password, :password_confirmation)

Slide 20

Slide 20 text

params.require(:user).permit(:username, :password, :password_confirmation) => POST /users Data: username=sikachu

Slide 21

Slide 21 text

params.require(:user).permit(:username, :password, :password_confirmation) => POST /users Data: username=sikachu <= 400 Bad Request

Slide 22

Slide 22 text

params.require(:user).permit(:username, :password, :password_confirmation) => POST /users Data: user[username]=sikachu

Slide 23

Slide 23 text

params.require(:user).permit(:username, :password, :password_confirmation) => POST /users Data: user[username]=sikachu <= 201 Created

Slide 24

Slide 24 text

params.require(:user).permit(:username, :password, :password_confirmation)

Slide 25

Slide 25 text

params.require(:user).permit(:username, :password, :password_confirmation) => POST /users Data: user[username]=sikachu&user[admin]=true

Slide 26

Slide 26 text

params.require(:user).permit(:username, :password, :password_confirmation) => POST /users Data: user[username]=sikachu&user[admin]=true <= 201 Created

Slide 27

Slide 27 text

params.require(:user).permit(:username, :password, :password_confirmation) => POST /users Data: user[username]=sikachu&user[admin]=true <= 201 Created irb> User.find_by_username('sikachu').admin? => false

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Only works in controller @user.update_attributes(name: 'sikachu', admin: true)

Slide 30

Slide 30 text

Try Out Today! https://github.com/rails/strong_parameters Fully compatible with Rails 3.2.8

Slide 31

Slide 31 text

ActiveSupport::Queue

Slide 32

Slide 32 text

*Not Finalized Yet* At the time of this presentation ...

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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)

Slide 35

Slide 35 text

Defaults • ActiveSupport::Queuing::Queue • Inherits from ::Queue (STDLIB) • ThreadConsumer will run the job in the background thread automatically.

Slide 36

Slide 36 text

Configurations # Default Container and Consumer config.queue = :asynchronous config.queue = :synchronous # Resque support in Resque 2.0.0.beta config.queue = :resque

Slide 37

Slide 37 text

Asynchronous ActionMailer

Slide 38

Slide 38 text

# config/application.rb config.action_mailer.async = true

Slide 39

Slide 39 text

Asynchronous ActionMailer Submitted by Brian Cardarella https://github.com/rails/rails/pull/6839

Slide 40

Slide 40 text

Cache Digests

Slide 41

Slide 41 text

Cache Digests “Russian Doll Caching”

Slide 42

Slide 42 text

Russian Doll Caching @topic

Slide 43

Slide 43 text

Russian Doll Caching @post @topic

Slide 44

Slide 44 text

Russian Doll Caching @post @user @topic

Slide 45

Slide 45 text

<%# app/views/topics/show.html.erb %> <% cache [ "v1", @topic ] do %>

<%= Topic.title %>

<%= 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

Slide 46

Slide 46 text

@post @user @topic Update Template

Slide 47

Slide 47 text

@topic @user @post Update Template

Slide 48

Slide 48 text

<%# 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

Slide 49

Slide 49 text

@topic @user @post Update Template

Slide 50

Slide 50 text

@topic @user @post Update Template

Slide 51

Slide 51 text

@topic @user @post Update Template

Slide 52

Slide 52 text

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 %>

Slide 53

Slide 53 text

@topic @user @post Update Template

Slide 54

Slide 54 text

@user @topic @post Update Template

Slide 55

Slide 55 text

@user @topic @post Update Template

Slide 56

Slide 56 text

@user @topic @post Update Template

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

Crazy!

Slide 59

Slide 59 text

Cache Digests

Slide 60

Slide 60 text

<%# app/views/topics/show.html.erb %> <% cache @topic do %>

<%= Topic.title %>

<%= 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

Slide 61

Slide 61 text

Generate MD5 of template and its dependencies as cache key views/topics/605816632-20120810191209/d9fb66b120b61f46707c67ab41d93cb2

Slide 62

Slide 62 text

Cache Expiration It just works!

Slide 63

Slide 63 text

$ rake cache_digests:dependencies TEMPLATE=topics/show [ "posts/post" ] $ rake cache_digests:nested_dependencies TEMPLATE=topics/show [ { "posts/post": [ "users/user" ] } ] Inspect Dependencies

Slide 64

Slide 64 text

Try Out Today! https://github.com/rails/cache_digests Fully compatible with Rails 3.2.8

Slide 65

Slide 65 text

Cached Schema Dump

Slide 66

Slide 66 text

Cached Schema Dump Speed up Rails startup time

Slide 67

Slide 67 text

$ 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

Slide 68

Slide 68 text

# config/environments/production.rb # Enabled by default config.active_record.use_schema_cache_dump = true

Slide 69

Slide 69 text

PATCH verb support

Slide 70

Slide 70 text

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.

Slide 71

Slide 71 text

<%= form_for @user do |f| %>
...

Slide 72

Slide 72 text

PUT /users/1 PATCH /users/1 => class UsersController < Appli def update end end

Slide 73

Slide 73 text

Routing Concern

Slide 74

Slide 74 text

Routing Concern Clean up duplicate routes

Slide 75

Slide 75 text

Before resources :messages do resources :comments end resources :posts do resources :comments resources :images, only: :index end

Slide 76

Slide 76 text

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]

Slide 77

Slide 77 text

ActiveRecord::Relation

Slide 78

Slide 78 text

Relation.first Relation.last

Slide 79

Slide 79 text

Relation.first Relation.last Always return record ordered by id

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

Relation.all

Slide 82

Slide 82 text

Relation.all Always return ActiveRecord::Relation object

Slide 83

Slide 83 text

Relation.all User.all # => #, #, ...]> User.to_a # => [#, #, ...]

Slide 84

Slide 84 text

Relation.none

Slide 85

Slide 85 text

Relation.none Returns ActiveRecord::NullRelation

Slide 86

Slide 86 text

Relation.none Still chainable!

Slide 87

Slide 87 text

# 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

Slide 88

Slide 88 text

# 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

Slide 89

Slide 89 text

# 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

Slide 90

Slide 90 text

# 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

Slide 91

Slide 91 text

Relation._____!

Slide 92

Slide 92 text

Relation._____! Mutates current relation

Slide 93

Slide 93 text

# 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

Slide 94

Slide 94 text

# 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

Slide 95

Slide 95 text

bind! create_with! eager_load! extending! from! group! having! includes! joins! limit! lock! offset! order! preload! readonly! references! reorder! reverse_order! select! uniq! where!

Slide 96

Slide 96 text

Deprecations

Slide 97

Slide 97 text

AR::Base.scoped

Slide 98

Slide 98 text

AR::Base.scoped Removed

Slide 99

Slide 99 text

AR::Base.scoped Use Model.all instead

Slide 100

Slide 100 text

Dynamic Finder Methods

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

Bring Back gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders' External dependency in Rails 4.0 (Remove in Rails 4.1)

Slide 103

Slide 103 text

Hash-based Finders

Slide 104

Slide 104 text

User.find(:first) User.find(:last, :order => 'id') User.find(:all, :conditions => { :active => true })

Slide 105

Slide 105 text

Bring Back gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders' External dependency in Rails 4.0 (Remove in Rails 4.1)

Slide 106

Slide 106 text

Eager Evaluated Scope

Slide 107

Slide 107 text

class User < ActiveRecord::Base scope :recent, where('created_at >= ?', 1.week.ago) end

Slide 108

Slide 108 text

class User < ActiveRecord::Base scope :recent, where('created_at >= ?', 1.week.ago) end

Slide 109

Slide 109 text

class User < ActiveRecord::Base scope :recent, where('created_at >= ?', 1.week.ago) end

Slide 110

Slide 110 text

Scope now requires a lambda

Slide 111

Slide 111 text

class User < ActiveRecord::Base scope :recent, -> { where('created_at >= ?', 1.week.ago) } end

Slide 112

Slide 112 text

ActiveRecord::SessionStore

Slide 113

Slide 113 text

ActiveRecord::SessionStore Extracted as a gem

Slide 114

Slide 114 text

gem 'activerecord-session_store', github: 'rails/activerecord_session_store' https://github.com/rails/activerecord-session_store

Slide 115

Slide 115 text

ActiveResource

Slide 116

Slide 116 text

ActiveResource Extracted as a gem

Slide 117

Slide 117 text

gem 'activeresource' https://github.com/rails/activeresource

Slide 118

Slide 118 text

Rails::Plugin

Slide 119

Slide 119 text

Rails::Plugin Removed

Slide 120

Slide 120 text

• Move it to your lib/ directory • Make it as a gem

Slide 121

Slide 121 text

New Deprecation Policy

Slide 122

Slide 122 text

SemVer Semantic Versioning

Slide 123

Slide 123 text

SemVer Semantic Versioning

Slide 124

Slide 124 text

Ver

Slide 125

Slide 125 text

Rails 3.1.x End of Life

Slide 126

Slide 126 text

Rails 3.2.x Some Deprecation Warnings (Support Until Rails 4.1.0 Comes Out)

Slide 127

Slide 127 text

Rails 4.0.0 Deprecation Warnings

Slide 128

Slide 128 text

Rails 4.1.0 Remove Deprecated Features

Slide 129

Slide 129 text

Smooth Upgrade From Rails 3.2.x to Rails 4.0.0

Slide 130

Slide 130 text

Release Candidate?

Slide 131

Slide 131 text

Release Candidate? Soon!

Slide 132

Slide 132 text

Try Now! # Gemfile # gem 'rails', '3.2.8' gem 'rails', github: 'rails/rails' $ bundle update

Slide 133

Slide 133 text

Report Bugs https://github.com/rails/rails/issues

Slide 134

Slide 134 text

Learn https://learn.thoughtbot.com/rails

Slide 135

Slide 135 text

Thank you! Prem Sichanugrist https://github.com/sikachu @sikachu Questions: #rails4