Ruby 2.0 / Rails 4.0, A selection of new features.

81
Ruby 2.0 / Rails 4.0 A selection of new features Evan Dorn Founder, Logical Reality Design http://lrdesign.com [email protected] @idahoev Friday, August 9, 13

description

A selection of new features features from Ruby 2.0 and Rails 4.0.

Transcript of Ruby 2.0 / Rails 4.0, A selection of new features.

Page 1: Ruby 2.0 / Rails 4.0, A selection of new features.

Ruby 2.0 / Rails 4.0A selection of new features

Evan DornFounder, Logical Reality Design

http://[email protected]

@idahoev

Friday, August 9, 13

Page 2: Ruby 2.0 / Rails 4.0, A selection of new features.

RUBY 2.0:A FEW COOL BITS

Friday, August 9, 13

Page 3: Ruby 2.0 / Rails 4.0, A selection of new features.

#to_h

hash representation, like to_a or to_s or

to_sym.

Friday, August 9, 13

Page 4: Ruby 2.0 / Rails 4.0, A selection of new features.

#to_h

Implemented on:•ENV•NilClass•Struct•Your classes!•ActiveRecord::Base (hopefully soon...)

Friday, August 9, 13

Page 5: Ruby 2.0 / Rails 4.0, A selection of new features.

#bsearch

Fast binary search!

•Array•Range

Friday, August 9, 13

Page 6: Ruby 2.0 / Rails 4.0, A selection of new features.

2.0.0p195 :003 > arr = [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19] => [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19]

#bsearch

Friday, August 9, 13

Page 7: Ruby 2.0 / Rails 4.0, A selection of new features.

2.0.0p195 :003 > arr = [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19] => [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19] 2.0.0p195 :004 > n = 0 => 0

#bsearch

Friday, August 9, 13

Page 8: Ruby 2.0 / Rails 4.0, A selection of new features.

2.0.0p195 :003 > arr = [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19] => [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19] 2.0.0p195 :004 > n = 0 => 0 2.0.0p195 :005 > arr.find{ |elem| p (n = n+1); elem == 11 }

#bsearch

Friday, August 9, 13

Page 9: Ruby 2.0 / Rails 4.0, A selection of new features.

2.0.0p195 :003 > arr = [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19] => [1, 3, 5, 7, 10, 11, 12, 14, 16, 18, 19] 2.0.0p195 :004 > n = 0 => 0 2.0.0p195 :005 > arr.find{ |elem| p (n = n+1); elem == 11 }1234567891011 => 11

#bsearch

Friday, August 9, 13

Page 10: Ruby 2.0 / Rails 4.0, A selection of new features.

2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 }

#bsearch

Friday, August 9, 13

Page 11: Ruby 2.0 / Rails 4.0, A selection of new features.

2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 }123 => 11

#bsearch

Friday, August 9, 13

Page 12: Ruby 2.0 / Rails 4.0, A selection of new features.

WARNING!

Friday, August 9, 13

Page 13: Ruby 2.0 / Rails 4.0, A selection of new features.

Undefined behavior if your Array is not

sorted!

Friday, August 9, 13

Page 14: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTS

•Hopefully improves the monkeypatch madness

•How many Core or StdLib classes does Rails extend?

•String

•Integer•Hash• Range• Array

•Regexp

•Proc•Date

•File

•Marshal

•Logger•NameError

•Numeric

•BigDecimal

•LoadError •Time

Friday, August 9, 13

Page 15: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTS

•Hopefully improves the monkeypatch madness

•How many Core or StdLib classes does Rails extend?

•String

•Integer•Hash• Range• Array

•Regexp

•Proc•Date

•File

•Marshal

•Logger•NameError

•Numeric

•BigDecimal

•LoadError •Time

•Module

•Class•Object

Friday, August 9, 13

Page 16: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTS

•What’s wrong with all this?

•“core” becomes a bit meaningless

•All loaded code sees these mutant core classes

•Harder to write gems that both with and without Rails

Friday, August 9, 13

Page 17: Ruby 2.0 / Rails 4.0, A selection of new features.

NON-REFINEMENTSmodule MyExtensions def do_stuff endend

class String include MyExtensionsend

# all loaded code sees String#do_stuff

# String.new.instance_methods changes...

# String.new.respond_to changes...

Friday, August 9, 13

Page 18: Ruby 2.0 / Rails 4.0, A selection of new features.

NON-REFINEMENTSmodule MyExtensions def do_stuff endend

class String include MyExtensionsend

# all loaded code sees String#do_stuff

# String.new.instance_methods changes...

# String.new.respond_to changes...

Friday, August 9, 13

Page 19: Ruby 2.0 / Rails 4.0, A selection of new features.

NON-REFINEMENTSmodule MyExtensions def do_stuff endend

class String include MyExtensionsend

# all loaded code sees String#do_stuff

# String.new.instance_methods changes...

# String.new.respond_to changes...

Friday, August 9, 13

Page 20: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTSmodule MyExtensions refine String do def do_stuff p “awesome!” end endend

String.new.do_stuff # undefined method “do_stuff”

using MyExtensions

String.new.do_stuff

=> “awesome!”

Friday, August 9, 13

Page 21: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTSmodule MyExtensions refine String do def do_stuff p “awesome!” end endend

String.new.do_stuff # undefined method “do_stuff”

using MyExtensions

String.new.do_stuff

=> “awesome!”

Friday, August 9, 13

Page 22: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTSmodule MyExtensions refine String do def do_stuff p “awesome!” end endend

String.new.do_stuff # undefined method “do_stuff”

using MyExtensions

String.new.do_stuff

=> “awesome!”

Friday, August 9, 13

Page 23: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTSmodule MyExtensions refine String do def do_stuff p “awesome!” end endend

String.new.do_stuff # undefined method “do_stuff”

using MyExtensions

String.new.do_stuff

=> “awesome!”

Friday, August 9, 13

Page 24: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTSmodule MyExtensions refine String do def do_stuff p “awesome!” end endend

String.new.do_stuff # undefined method “do_stuff”

using MyExtensions

String.new.do_stuff

=> “awesome!”

Friday, August 9, 13

Page 25: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTSmodule MyExtensions refine String do def do_stuff p “awesome!” end endend

String.new.do_stuff # undefined method “do_stuff”

using MyExtensions

String.new.do_stuff

=> “awesome!”

Friday, August 9, 13

Page 26: Ruby 2.0 / Rails 4.0, A selection of new features.

REFINEMENTSmodule MyExtensions refine String do def do_stuff p “awesome!” end endend

String.new.do_stuff # undefined method “do_stuff”

using MyExtensions

String.new.do_stuff

=> “awesome!”

Friday, August 9, 13

Page 27: Ruby 2.0 / Rails 4.0, A selection of new features.

KEYWORD ARGUMENTS

•my_method(options = {}) has problems

•assigning defaults with merge({...}) is fugly

•options[:mispeled_arg] silently returns nil!

•options = {} allocates a new hash on every call

Friday, August 9, 13

Page 28: Ruby 2.0 / Rails 4.0, A selection of new features.

KEYWORD ARGUMENTSdef my_method(arg1: ‘foo’, arg2: 123) p arg1 p arg2end

my_method“foo” 123=> 123

Friday, August 9, 13

Page 29: Ruby 2.0 / Rails 4.0, A selection of new features.

KEYWORD ARGUMENTSdef my_method(arg1: ‘foo’, arg2: 123) p arg1 p arg2end

my_method“foo” 123=> 123

Friday, August 9, 13

Page 30: Ruby 2.0 / Rails 4.0, A selection of new features.

WARNING!

Friday, August 9, 13

Page 31: Ruby 2.0 / Rails 4.0, A selection of new features.

THOSE ARGS ARE NOT A HASH!

Friday, August 9, 13

Page 32: Ruby 2.0 / Rails 4.0, A selection of new features.

KEYWORD ARGUMENTSdef my_method(:arg1 => 'foo', :arg2 => 123) # doesn’t workend

SyntaxError: (irb):27: syntax error, unexpected tSYMBEG, expecting ')'def my_method(:arg1 => 'foo', :arg2 => 123) ^

Friday, August 9, 13

Page 33: Ruby 2.0 / Rails 4.0, A selection of new features.

KEYWORD ARGUMENTSdef my_method(:arg1 => 'foo', :arg2 => 123) # doesn’t workend

SyntaxError: (irb):27: syntax error, unexpected tSYMBEG, expecting ')'def my_method(:arg1 => 'foo', :arg2 => 123) ^

Friday, August 9, 13

Page 34: Ruby 2.0 / Rails 4.0, A selection of new features.

MODULE#PREPEND •I didn’t have time to write this slide!

•But the feature is awesome, I promise!

Friday, August 9, 13

Page 35: Ruby 2.0 / Rails 4.0, A selection of new features.

Friday, August 9, 13

Page 36: Ruby 2.0 / Rails 4.0, A selection of new features.

SAD PUPPY

Friday, August 9, 13

Page 37: Ruby 2.0 / Rails 4.0, A selection of new features.

RAILS 4.0!

Friday, August 9, 13

Page 38: Ruby 2.0 / Rails 4.0, A selection of new features.

MASS-ASSIGNMENTPROTECTION

•No more “attr_accessible” in the Model

•It’s a controller concern

•... because it’s often different in different controllers

•(admin controllers, etc.)

Friday, August 9, 13

Page 39: Ruby 2.0 / Rails 4.0, A selection of new features.

STRONG PARAMSclass UsersController < ApplicationController def update user = User.find(params[:id]) if user.update_attributes(user_params) # see below redirect_to home_path else render :edit end end private # Require that :user be a key in the params Hash, # and only accept :first, :last, and :email attributes def user_params params.require(:user).permit(:first, :last, :email) endend

Friday, August 9, 13

Page 40: Ruby 2.0 / Rails 4.0, A selection of new features.

STRONG PARAMSclass UsersController < ApplicationController def update user = User.find(params[:id]) if user.update_attributes(user_params) # see below redirect_to home_path else render :edit end end private # Require that :user be a key in the params Hash, # and only accept :first, :last, and :email attributes def user_params params.require(:user).permit(:first, :last, :email) endend

Friday, August 9, 13

Page 41: Ruby 2.0 / Rails 4.0, A selection of new features.

STRONG PARAMSclass UsersController < ApplicationController def update user = User.find(params[:id]) if user.update_attributes(user_params) # see below redirect_to home_path else render :edit end end private # Require that :user be a key in the params Hash, # and only accept :first, :last, and :email attributes def user_params params.require(:user).permit(:first, :last, :email) endend

Friday, August 9, 13

Page 42: Ruby 2.0 / Rails 4.0, A selection of new features.

STRONG PARAMSclass UsersController < ApplicationController def update user = User.find(params[:id]) if user.update_attributes(user_params) # see below redirect_to home_path else render :edit end end private # Require that :user be a key in the params Hash, # and only accept :first, :last, and :email attributes def user_params params.require(:user).permit(:first, :last, :email) endend

Friday, August 9, 13

Page 43: Ruby 2.0 / Rails 4.0, A selection of new features.

STRONG PARAMS

•Params hashes get some new methods

•e.g. params.permitted?

•params hash will contain only the permitted keys

•No deep permits: if the Hash contains a Hash, you must permit nested keys specifically

Friday, August 9, 13

Page 44: Ruby 2.0 / Rails 4.0, A selection of new features.

Friday, August 9, 13

Page 45: Ruby 2.0 / Rails 4.0, A selection of new features.

FRAGMENT CACHING

•Caching HTML fragments can be a huge speedup

•Expiring fragments correctly is a bitch

•... especially if they’re nested

•... and slow if you have a lot of cache keys

Friday, August 9, 13

Page 46: Ruby 2.0 / Rails 4.0, A selection of new features.

OLD BUSTED CACHING%h2 To-do List- cache “todo_for_#{current_user.id}” do %table - @todo_items.each do |item| - cache “todo_item_#{item.id}” do %tr %td= item.name %td= item.importance

Friday, August 9, 13

Page 47: Ruby 2.0 / Rails 4.0, A selection of new features.

OLD BUSTED CACHING%h2 To-do List- cache “todo_for_#{current_user.id}” do %table - @todo_items.each do |item| - cache “todo_item_#{item.id}” do %tr %td= item.name %td= item.importance

Friday, August 9, 13

Page 48: Ruby 2.0 / Rails 4.0, A selection of new features.

RUSSIAN DOLL CACHING

•Important changes:

•cache(key) do ...end takes an Array for the key

•key generation concatenates the array elements

•after calling #cache_key on any members that respond to that method

Friday, August 9, 13

Page 49: Ruby 2.0 / Rails 4.0, A selection of new features.

NEW HOTNESS CACHING%h2 To-do List- cache [ :todo_list, current_user, @todo_list ] do %table - @todo_list.items.each do |item| - cache [ :todo_item, item ] do %tr %td= item.name %td= item.importance

Friday, August 9, 13

Page 50: Ruby 2.0 / Rails 4.0, A selection of new features.

NEW HOTNESS CACHING%h2 To-do List- cache [ :todo_list, current_user, todo_list ] do %table - @todo_list.items.each do |item| - cache [ :todo_item, item ] do %tr %td= item.name %td= item.importance

Friday, August 9, 13

Page 51: Ruby 2.0 / Rails 4.0, A selection of new features.

class TodoItem < ActiveRecord::Base def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” endend

class TodoList # A presenter attr_accessor :items # array of items attr_accessor :user # User object def cache_key “#{user.id}-#{items.newest.updated_at.to_s(:number)“ end end

Friday, August 9, 13

Page 52: Ruby 2.0 / Rails 4.0, A selection of new features.

class TodoItem < ActiveRecord::Base def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” endend

class TodoList # A presenter attr_accessor :items # array of items attr_accessor :user # User object def cache_key “#{user.id}-#{items.newest.updated_at.to_s(:number)“ end end

Friday, August 9, 13

Page 53: Ruby 2.0 / Rails 4.0, A selection of new features.

class TodoItem < ActiveRecord:: Base def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” endend

class TodoList # A Presenter attr_accessor :items # array of items attr_accessor :user # User object def cache_key “#{user.id}-#{items.newest.updated_at.to_s(:number)“ end end

Friday, August 9, 13

Page 54: Ruby 2.0 / Rails 4.0, A selection of new features.

class TodoItem def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” endend

class TodoList attr_accessor :items # array of items attr_accessor :user # User object def cache_key “#{items.newest.updated_at.to_s(:number)“ end end

Friday, August 9, 13

Page 55: Ruby 2.0 / Rails 4.0, A selection of new features.

class TodoItem def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” endend

class TodoList attr_accessor :items # array of items attr_accessor :user # User object def cache_key “#{items.newest.updated_at.to_s(:number)“ end end

class User < ActiveRecord::Base def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” end end

Friday, August 9, 13

Page 56: Ruby 2.0 / Rails 4.0, A selection of new features.

NEW HOTNESS CACHING%h2 To-do List- cache [ :todo_list, current_user, todo_list ] do -# “todo_list/1234-201308081234/201308081146” %table - @todo_list.items.each do |item| - cache [ :todo_item, item ] do %tr %td= item.name %td= item.importance

Friday, August 9, 13

Page 57: Ruby 2.0 / Rails 4.0, A selection of new features.

NEW HOTNESS CACHING%h2 To-do List- cache [ :todo_list, current_user, todo_list ] do -# “todo_list/1234-201308081234/201308081146” %table - @todo_list.items.each do |item| - cache [ :todo_item, item ] do -# “todo_item/5316-201306071156” %tr %td= item.name %td= item.importance

Friday, August 9, 13

Page 58: Ruby 2.0 / Rails 4.0, A selection of new features.

RUSSIAN DOLL CACHING

•With clever key construction:

•Every model update causes a cache miss

•... Never have to invalidate fragments!

•Any decent memory store will expire unused keys for you

Friday, August 9, 13

Page 59: Ruby 2.0 / Rails 4.0, A selection of new features.

PSST... A SECRET:You can do this in Rails 3, too.

Just write your own smart cache key helpers.

Friday, August 9, 13

Page 60: Ruby 2.0 / Rails 4.0, A selection of new features.

PATCH•PUT is no longer the default HTTP method for #update

actions.

•(Because PUT is defined to be whole-object, never partial, and should avoid side-effects.)

•Use PATCH instead

•Affects: config/routes.rb, tests, etc.

Friday, August 9, 13

Page 61: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODEL

•Turns any object into a proper model

•For use with form_for(), etc.

•attr_accessors become AM-style attributes

•Adds name introspection, conversion, I18n support, validations, etc...

Friday, August 9, 13

Page 62: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODEL

Helps to break the tendency to equate “resource” with “ActiveRecord Model.”

Friday, August 9, 13

Page 63: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODELclass UserFormModel include ActiveModel::Model

def new(user) @user = user @settings = user.settings end

attr_accessor :name, :admin

def persisted? @user.persisted? end

def persist! @user.name = name @user.save! @settings.admin = admin @settings.save! endend

Friday, August 9, 13

Page 64: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODELclass UserFormModel include ActiveModel::Model

def new(user) @user = user @settings = user.settings end

attr_accessor :name, :admin

def persisted? @user.persisted? end

def persist! @user.name = name @user.save! @settings.admin = admin @settings.save! end

Friday, August 9, 13

Page 65: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODELclass UserFormModel include ActiveModel::Model

def new(user) @user = user @settings = user.settings end

attr_accessor :name, :admin

def persisted? @user.persisted? end

def persist! @user.name = name @user.save! @settings.admin = admin @settings.save! end

Friday, August 9, 13

Page 66: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODELclass UserFormModel include ActiveModel::Model

def new(user) @user = user @settings = user.settings end

attr_accessor :name, :admin

def persisted? # default false if not overridden! @user.persisted? end

def persist! @user.name = name @user.save! @settings.admin = admin @settings.save! endend

Friday, August 9, 13

Page 67: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODELclass UserFormModel include ActiveModel::Model

def new(user) @user = user @settings = user.settings end

attr_accessor :name, :admin

def persisted? @user.persisted? end

def persist! @user.name = name @user.save! @settings.admin = admin @settings.save! endend

Friday, August 9, 13

Page 68: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODEL# /app/views/users/_form

= form_for(@user_form_model) = f.input(:name) = f.check_box(:admin) = f.submit!

Friday, August 9, 13

Page 69: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIVEMODEL::MODEL# /app/views/users/_form

= form_for(@user_form_model) = f.input(:name) = f.check_box(:admin) = f.submit!

Friday, August 9, 13

Page 70: Ruby 2.0 / Rails 4.0, A selection of new features.

AVOIDING FULL PAGE LOADS

Friday, August 9, 13

Page 71: Ruby 2.0 / Rails 4.0, A selection of new features.

CHECK OUT “TURBOLINKS”

Friday, August 9, 13

Page 72: Ruby 2.0 / Rails 4.0, A selection of new features.

OR JUST USE:•AngularJS•EmberJS•Backbone•etc...

Friday, August 9, 13

Page 73: Ruby 2.0 / Rails 4.0, A selection of new features.

‘cause that’s probably the

right tool,really.

Friday, August 9, 13

Page 74: Ruby 2.0 / Rails 4.0, A selection of new features.

STREAMING SUPPORT!

Friday, August 9, 13

Page 75: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIONCONTROLLER::LIVEclass MyController < ActionController::Base include ActionController::Live

def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello world\n" sleep 1 } ensure response.stream.close end

end

Friday, August 9, 13

Page 76: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIONCONTROLLER::LIVEclass MyController < ActionController::Base include ActionController::Live

def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello world\n" sleep 1 } ensure response.stream.close end

end

Friday, August 9, 13

Page 77: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIONCONTROLLER::LIVEclass MyController < ActionController::Base include ActionController::Live

def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello world\n" sleep 1 } ensure response.stream.close end

end

Friday, August 9, 13

Page 78: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIONCONTROLLER::LIVEclass MyController < ActionController::Base include ActionController::Live

def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello world\n" sleep 1 } ensure response.stream.close end

end

Friday, August 9, 13

Page 79: Ruby 2.0 / Rails 4.0, A selection of new features.

ACTIONCONTROLLER::LIVE

•Don’t try to change headers after calling response.stream.write...

•Don’t forget to close...

•Stream actions automatically happen in a separate thread.

•(So make sure it’s thread-safe!)

Friday, August 9, 13

Page 80: Ruby 2.0 / Rails 4.0, A selection of new features.

ANY TIME LEFT? (IF SO, I’LL DO

MODULE#PREPEND ON A WHITEBOARD OR SOMETHING.)

Friday, August 9, 13