Ruby 2.0 / Rails 4.0
A selection of new features
Evan Dorn
Founder, Logical Reality Design
http://lrdesign.com
evan@lrdesi...
RUBY 2.0:
A FEW COOL BITS
Friday, August 9, 13
#to_h
hash representation,
like to_a or to_s or
to_sym.
Friday, August 9, 13
#to_h
Implemented on:
•ENV
•NilClass
•Struct
•Your classes!
•ActiveRecord::Base
(hopefully soon...)
Friday, August 9, 13
#bsearch
Fast binary search!
•Array
•Range
Friday, August 9, 13
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
Frida...
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...
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...
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...
2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 }
#bsearch
Friday, August 9, 13
2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 }
1
2
3
=> 11
#bsearch
Friday, August 9, 13
WARNING!
Friday, August 9, 13
Undefined behavior if
your Array is not
sorted!
Friday, August 9, 13
REFINEMENTS
•Hopefully improves the monkeypatch madness
•How many Core or StdLib classes does Rails extend?
•String
•Integ...
REFINEMENTS
•Hopefully improves the monkeypatch madness
•How many Core or StdLib classes does Rails extend?
•String
•Integ...
REFINEMENTS
•What’s wrong with all this?
•“core” becomes a bit meaningless
•All loaded code sees these mutant core classes...
NON-REFINEMENTS
module MyExtensions
def do_stuff
end
end
class String
include MyExtensions
end
# all loaded code sees Stri...
NON-REFINEMENTS
module MyExtensions
def do_stuff
end
end
class String
include MyExtensions
end
# all loaded code sees Stri...
NON-REFINEMENTS
module MyExtensions
def do_stuff
end
end
class String
include MyExtensions
end
# all loaded code sees Stri...
REFINEMENTS
module MyExtensions
refine String do
def do_stuff
p “awesome!”
end
end
end
String.new.do_stuff # undefined met...
REFINEMENTS
module MyExtensions
refine String do
def do_stuff
p “awesome!”
end
end
end
String.new.do_stuff # undefined met...
REFINEMENTS
module MyExtensions
refine String do
def do_stuff
p “awesome!”
end
end
end
String.new.do_stuff # undefined met...
REFINEMENTS
module MyExtensions
refine String do
def do_stuff
p “awesome!”
end
end
end
String.new.do_stuff # undefined met...
REFINEMENTS
module MyExtensions
refine String do
def do_stuff
p “awesome!”
end
end
end
String.new.do_stuff # undefined met...
REFINEMENTS
module MyExtensions
refine String do
def do_stuff
p “awesome!”
end
end
end
String.new.do_stuff # undefined met...
REFINEMENTS
module MyExtensions
refine String do
def do_stuff
p “awesome!”
end
end
end
String.new.do_stuff # undefined met...
KEYWORD ARGUMENTS
•my_method(options = {}) has problems
•assigning defaults with merge({...}) is fugly
•options[:mispeled_...
KEYWORD ARGUMENTS
def my_method(arg1: ‘foo’, arg2: 123)
p arg1
p arg2
end
my_method
“foo”
123
=> 123
Friday, August 9, 13
KEYWORD ARGUMENTS
def my_method(arg1: ‘foo’, arg2: 123)
p arg1
p arg2
end
my_method
“foo”
123
=> 123
Friday, August 9, 13
WARNING!
Friday, August 9, 13
THOSE ARGS ARE
NOT A HASH!
Friday, August 9, 13
KEYWORD ARGUMENTS
def my_method(:arg1 => 'foo', :arg2 => 123)
# doesn’t work
end
SyntaxError: (irb):27: syntax error, unex...
KEYWORD ARGUMENTS
def my_method(:arg1 => 'foo', :arg2 => 123)
# doesn’t work
end
SyntaxError: (irb):27: syntax error, unex...
MODULE#PREPEND
•I didn’t have time to write this slide!
•But the feature is awesome, I promise!
Friday, August 9, 13
Friday, August 9, 13
SAD PUPPY
Friday, August 9, 13
RAILS 4.0!
Friday, August 9, 13
MASS-ASSIGNMENT
PROTECTION
•No more “attr_accessible” in the Model
•It’s a controller concern
•... because it’s often diff...
STRONG PARAMS
class UsersController < ApplicationController
def update
user = User.find(params[:id])
if user.update_attrib...
STRONG PARAMS
class UsersController < ApplicationController
def update
user = User.find(params[:id])
if user.update_attrib...
STRONG PARAMS
class UsersController < ApplicationController
def update
user = User.find(params[:id])
if user.update_attrib...
STRONG PARAMS
class UsersController < ApplicationController
def update
user = User.find(params[:id])
if user.update_attrib...
STRONG PARAMS
•Params hashes get some new methods
•e.g. params.permitted?
•params hash will contain only the permitted key...
Friday, August 9, 13
FRAGMENT CACHING
•Caching HTML fragments can be a huge speedup
•Expiring fragments correctly is a bitch
•... especially if...
OLD BUSTED CACHING
%h2 To-do List
- cache “todo_for_#{current_user.id}” do
%table
- @todo_items.each do |item|
- cache “to...
OLD BUSTED CACHING
%h2 To-do List
- cache “todo_for_#{current_user.id}” do
%table
- @todo_items.each do |item|
- cache “to...
RUSSIAN DOLL CACHING
•Important changes:
•cache(key) do ...end takes an Array for the key
•key generation concatenates the...
NEW HOTNESS CACHING
%h2 To-do List
- cache [ :todo_list, current_user, @todo_list ] do
%table
- @todo_list.items.each do |...
NEW HOTNESS CACHING
%h2 To-do List
- cache [ :todo_list, current_user, todo_list ] do
%table
- @todo_list.items.each do |i...
class TodoItem < ActiveRecord::Base
def cache_key
“#{self.id}-#{self.updated_at.to_s(:number)}”
end
end
class TodoList # A...
class TodoItem < ActiveRecord::Base
def cache_key
“#{self.id}-#{self.updated_at.to_s(:number)}”
end
end
class TodoList # A...
class TodoItem < ActiveRecord:: Base
def cache_key
“#{self.id}-#{self.updated_at.to_s(:number)}”
end
end
class TodoList # ...
class TodoItem
def cache_key
“#{self.id}-#{self.updated_at.to_s(:number)}”
end
end
class TodoList
attr_accessor :items # a...
class TodoItem
def cache_key
“#{self.id}-#{self.updated_at.to_s(:number)}”
end
end
class TodoList
attr_accessor :items # a...
NEW HOTNESS CACHING
%h2 To-do List
- cache [ :todo_list, current_user, todo_list ] do
-# “todo_list/1234-201308081234/2013...
NEW HOTNESS CACHING
%h2 To-do List
- cache [ :todo_list, current_user, todo_list ] do
-# “todo_list/1234-201308081234/2013...
RUSSIAN DOLL CACHING
•With clever key construction:
•Every model update causes a cache miss
•... Never have to invalidate ...
PSST... A SECRET:
You can do this in Rails 3, too.
Just write your own smart cache key
helpers.
Friday, August 9, 13
PATCH
•PUT is no longer the default HTTP method for #update
actions.
•(Because PUT is defined to be whole-object, never
par...
ACTIVEMODEL::MODEL
•Turns any object into a proper model
•For use with form_for(), etc.
•attr_accessors become AM-style at...
ACTIVEMODEL::MODEL
Helps to break the tendency to equate “resource”
with “ActiveRecord Model.”
Friday, August 9, 13
ACTIVEMODEL::MODEL
class UserFormModel
include ActiveModel::Model
def new(user)
@user = user
@settings = user.settings
end...
ACTIVEMODEL::MODEL
class UserFormModel
include ActiveModel::Model
def new(user)
@user = user
@settings = user.settings
end...
ACTIVEMODEL::MODEL
class UserFormModel
include ActiveModel::Model
def new(user)
@user = user
@settings = user.settings
end...
ACTIVEMODEL::MODEL
class UserFormModel
include ActiveModel::Model
def new(user)
@user = user
@settings = user.settings
end...
ACTIVEMODEL::MODEL
class UserFormModel
include ActiveModel::Model
def new(user)
@user = user
@settings = user.settings
end...
ACTIVEMODEL::MODEL
# /app/views/users/_form
= form_for(@user_form_model)
= f.input(:name)
= f.check_box(:admin)
= f.submit...
ACTIVEMODEL::MODEL
# /app/views/users/_form
= form_for(@user_form_model)
= f.input(:name)
= f.check_box(:admin)
= f.submit...
AVOIDING FULL
PAGE LOADS
Friday, August 9, 13
CHECK OUT
“TURBOLINKS”
Friday, August 9, 13
OR JUST USE:
•AngularJS
•EmberJS
•Backbone
•etc...
Friday, August 9, 13
‘cause that’s
probably the
right tool,
really.
Friday, August 9, 13
STREAMING SUPPORT!
Friday, August 9, 13
ACTIONCONTROLLER::LIVE
class MyController < ActionController::Base
include ActionController::Live
def stream
response.head...
ACTIONCONTROLLER::LIVE
class MyController < ActionController::Base
include ActionController::Live
def stream
response.head...
ACTIONCONTROLLER::LIVE
class MyController < ActionController::Base
include ActionController::Live
def stream
response.head...
ACTIONCONTROLLER::LIVE
class MyController < ActionController::Base
include ActionController::Live
def stream
response.head...
ACTIONCONTROLLER::LIVE
•Don’t try to change headers after calling
response.stream.write...
•Don’t forget to close...
•Stre...
ANY TIME LEFT?
(IF SO, I’LL DO
MODULE#PREPEND ON A
WHITEBOARD OR SOMETHING.)
Friday, August 9, 13
Thanks!
Evan Dorn
Founder, Logical Reality Design
http://lrdesign.com
evan@lrdesign.com
@idahoev
Friday, August 9, 13
Upcoming SlideShare
Loading in …5
×

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

967 views

Published on

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

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
967
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
7
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

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

  1. 1. Ruby 2.0 / Rails 4.0 A selection of new features Evan Dorn Founder, Logical Reality Design http://lrdesign.com evan@lrdesign.com @idahoev Friday, August 9, 13
  2. 2. RUBY 2.0: A FEW COOL BITS Friday, August 9, 13
  3. 3. #to_h hash representation, like to_a or to_s or to_sym. Friday, August 9, 13
  4. 4. #to_h Implemented on: •ENV •NilClass •Struct •Your classes! •ActiveRecord::Base (hopefully soon...) Friday, August 9, 13
  5. 5. #bsearch Fast binary search! •Array •Range Friday, August 9, 13
  6. 6. 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
  7. 7. 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
  8. 8. 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
  9. 9. 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 } 1 2 3 4 5 6 7 8 9 10 11 => 11 #bsearch Friday, August 9, 13
  10. 10. 2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 } #bsearch Friday, August 9, 13
  11. 11. 2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 } 1 2 3 => 11 #bsearch Friday, August 9, 13
  12. 12. WARNING! Friday, August 9, 13
  13. 13. Undefined behavior if your Array is not sorted! Friday, August 9, 13
  14. 14. 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
  15. 15. 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
  16. 16. 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
  17. 17. NON-REFINEMENTS module MyExtensions def do_stuff end end class String include MyExtensions end # all loaded code sees String#do_stuff # String.new.instance_methods changes... # String.new.respond_to changes... Friday, August 9, 13
  18. 18. NON-REFINEMENTS module MyExtensions def do_stuff end end class String include MyExtensions end # all loaded code sees String#do_stuff # String.new.instance_methods changes... # String.new.respond_to changes... Friday, August 9, 13
  19. 19. NON-REFINEMENTS module MyExtensions def do_stuff end end class String include MyExtensions end # all loaded code sees String#do_stuff # String.new.instance_methods changes... # String.new.respond_to changes... Friday, August 9, 13
  20. 20. REFINEMENTS module MyExtensions refine String do def do_stuff p “awesome!” end end end String.new.do_stuff # undefined method “do_stuff” using MyExtensions String.new.do_stuff => “awesome!” Friday, August 9, 13
  21. 21. REFINEMENTS module MyExtensions refine String do def do_stuff p “awesome!” end end end String.new.do_stuff # undefined method “do_stuff” using MyExtensions String.new.do_stuff => “awesome!” Friday, August 9, 13
  22. 22. REFINEMENTS module MyExtensions refine String do def do_stuff p “awesome!” end end end String.new.do_stuff # undefined method “do_stuff” using MyExtensions String.new.do_stuff => “awesome!” Friday, August 9, 13
  23. 23. REFINEMENTS module MyExtensions refine String do def do_stuff p “awesome!” end end end String.new.do_stuff # undefined method “do_stuff” using MyExtensions String.new.do_stuff => “awesome!” Friday, August 9, 13
  24. 24. REFINEMENTS module MyExtensions refine String do def do_stuff p “awesome!” end end end String.new.do_stuff # undefined method “do_stuff” using MyExtensions String.new.do_stuff => “awesome!” Friday, August 9, 13
  25. 25. REFINEMENTS module MyExtensions refine String do def do_stuff p “awesome!” end end end String.new.do_stuff # undefined method “do_stuff” using MyExtensions String.new.do_stuff => “awesome!” Friday, August 9, 13
  26. 26. REFINEMENTS module MyExtensions refine String do def do_stuff p “awesome!” end end end String.new.do_stuff # undefined method “do_stuff” using MyExtensions String.new.do_stuff => “awesome!” Friday, August 9, 13
  27. 27. 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
  28. 28. KEYWORD ARGUMENTS def my_method(arg1: ‘foo’, arg2: 123) p arg1 p arg2 end my_method “foo” 123 => 123 Friday, August 9, 13
  29. 29. KEYWORD ARGUMENTS def my_method(arg1: ‘foo’, arg2: 123) p arg1 p arg2 end my_method “foo” 123 => 123 Friday, August 9, 13
  30. 30. WARNING! Friday, August 9, 13
  31. 31. THOSE ARGS ARE NOT A HASH! Friday, August 9, 13
  32. 32. KEYWORD ARGUMENTS def my_method(:arg1 => 'foo', :arg2 => 123) # doesn’t work end SyntaxError: (irb):27: syntax error, unexpected tSYMBEG, expecting ')' def my_method(:arg1 => 'foo', :arg2 => 123) ^ Friday, August 9, 13
  33. 33. KEYWORD ARGUMENTS def my_method(:arg1 => 'foo', :arg2 => 123) # doesn’t work end SyntaxError: (irb):27: syntax error, unexpected tSYMBEG, expecting ')' def my_method(:arg1 => 'foo', :arg2 => 123) ^ Friday, August 9, 13
  34. 34. MODULE#PREPEND •I didn’t have time to write this slide! •But the feature is awesome, I promise! Friday, August 9, 13
  35. 35. Friday, August 9, 13
  36. 36. SAD PUPPY Friday, August 9, 13
  37. 37. RAILS 4.0! Friday, August 9, 13
  38. 38. MASS-ASSIGNMENT PROTECTION •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
  39. 39. STRONG PARAMS class 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) end end Friday, August 9, 13
  40. 40. STRONG PARAMS class 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) end end Friday, August 9, 13
  41. 41. STRONG PARAMS class 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) end end Friday, August 9, 13
  42. 42. STRONG PARAMS class 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) end end Friday, August 9, 13
  43. 43. 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
  44. 44. Friday, August 9, 13
  45. 45. 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
  46. 46. 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
  47. 47. 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
  48. 48. 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
  49. 49. 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
  50. 50. 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
  51. 51. class TodoItem < ActiveRecord::Base def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” end end 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
  52. 52. class TodoItem < ActiveRecord::Base def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” end end 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
  53. 53. class TodoItem < ActiveRecord:: Base def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” end end 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
  54. 54. class TodoItem def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” end end 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
  55. 55. class TodoItem def cache_key “#{self.id}-#{self.updated_at.to_s(:number)}” end end 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
  56. 56. 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
  57. 57. 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
  58. 58. 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
  59. 59. PSST... A SECRET: You can do this in Rails 3, too. Just write your own smart cache key helpers. Friday, August 9, 13
  60. 60. 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
  61. 61. 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
  62. 62. ACTIVEMODEL::MODEL Helps to break the tendency to equate “resource” with “ActiveRecord Model.” Friday, August 9, 13
  63. 63. ACTIVEMODEL::MODEL class 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 end Friday, August 9, 13
  64. 64. ACTIVEMODEL::MODEL class 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
  65. 65. ACTIVEMODEL::MODEL class 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
  66. 66. ACTIVEMODEL::MODEL class 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! end end Friday, August 9, 13
  67. 67. ACTIVEMODEL::MODEL class 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 end Friday, August 9, 13
  68. 68. ACTIVEMODEL::MODEL # /app/views/users/_form = form_for(@user_form_model) = f.input(:name) = f.check_box(:admin) = f.submit! Friday, August 9, 13
  69. 69. ACTIVEMODEL::MODEL # /app/views/users/_form = form_for(@user_form_model) = f.input(:name) = f.check_box(:admin) = f.submit! Friday, August 9, 13
  70. 70. AVOIDING FULL PAGE LOADS Friday, August 9, 13
  71. 71. CHECK OUT “TURBOLINKS” Friday, August 9, 13
  72. 72. OR JUST USE: •AngularJS •EmberJS •Backbone •etc... Friday, August 9, 13
  73. 73. ‘cause that’s probably the right tool, really. Friday, August 9, 13
  74. 74. STREAMING SUPPORT! Friday, August 9, 13
  75. 75. ACTIONCONTROLLER::LIVE class MyController < ActionController::Base include ActionController::Live def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello worldn" sleep 1 } ensure response.stream.close end end Friday, August 9, 13
  76. 76. ACTIONCONTROLLER::LIVE class MyController < ActionController::Base include ActionController::Live def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello worldn" sleep 1 } ensure response.stream.close end end Friday, August 9, 13
  77. 77. ACTIONCONTROLLER::LIVE class MyController < ActionController::Base include ActionController::Live def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello worldn" sleep 1 } ensure response.stream.close end end Friday, August 9, 13
  78. 78. ACTIONCONTROLLER::LIVE class MyController < ActionController::Base include ActionController::Live def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello worldn" sleep 1 } ensure response.stream.close end end Friday, August 9, 13
  79. 79. 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
  80. 80. ANY TIME LEFT? (IF SO, I’LL DO MODULE#PREPEND ON A WHITEBOARD OR SOMETHING.) Friday, August 9, 13
  81. 81. Thanks! Evan Dorn Founder, Logical Reality Design http://lrdesign.com evan@lrdesign.com @idahoev Friday, August 9, 13

×