SlideShare une entreprise Scribd logo
1  sur  81
Télécharger pour lire hors ligne
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
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
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]
2.0.0p195 :004 > n = 0
=> 0
#bsearch
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]
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
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
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
•Integer
•Hash
• Range
• Array
•Regexp
•Proc
•Date
•File
•Marshal
•Logger
•NameError
•Numeric
•BigDecimal
•LoadError
•Time
Friday, August 9, 13
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
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
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
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
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
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
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
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
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
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
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
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
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
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, unexpected tSYMBEG, expecting ')'
def my_method(:arg1 => 'foo', :arg2 => 123)
^
Friday, August 9, 13
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
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 different in different controllers
•(admin controllers, etc.)
Friday, August 9, 13
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
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
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
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
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
Friday, August 9, 13
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
partial, and should avoid side-effects.)
•Use PATCH instead
•Affects: config/routes.rb, tests, etc.
Friday, August 9, 13
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
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
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
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
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
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
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
ACTIVEMODEL::MODEL
# /app/views/users/_form
= form_for(@user_form_model)
= f.input(:name)
= f.check_box(:admin)
= f.submit!
Friday, August 9, 13
ACTIVEMODEL::MODEL
# /app/views/users/_form
= form_for(@user_form_model)
= f.input(:name)
= f.check_box(:admin)
= f.submit!
Friday, August 9, 13
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.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
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
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
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
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
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

Contenu connexe

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

Ruby 入門 第一次就上手
Ruby 入門 第一次就上手Ruby 入門 第一次就上手
Ruby 入門 第一次就上手
Wen-Tien Chang
 
Introducing Modern Perl
Introducing Modern PerlIntroducing Modern Perl
Introducing Modern Perl
Dave Cross
 
Pgbr 2013 postgres on aws
Pgbr 2013   postgres on awsPgbr 2013   postgres on aws
Pgbr 2013 postgres on aws
Emanuel Calvo
 
APMG juni 2014 - Regular Expression
APMG juni 2014 - Regular ExpressionAPMG juni 2014 - Regular Expression
APMG juni 2014 - Regular Expression
Byte
 

Similaire à Ruby 2.0 / Rails 4.0, A selection of new features. (20)

Mastering ElasticSearch with Ruby and Tire
Mastering ElasticSearch with Ruby and TireMastering ElasticSearch with Ruby and Tire
Mastering ElasticSearch with Ruby and Tire
 
Expressjs basic to advance, power by Node.js
Expressjs basic to advance, power by Node.jsExpressjs basic to advance, power by Node.js
Expressjs basic to advance, power by Node.js
 
Ruby101
Ruby101Ruby101
Ruby101
 
elasticsearch basics workshop
elasticsearch basics workshopelasticsearch basics workshop
elasticsearch basics workshop
 
How We Look At Software
How We Look At SoftwareHow We Look At Software
How We Look At Software
 
The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013The Future of JRuby - Baruco 2013
The Future of JRuby - Baruco 2013
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
SassConf: It takes a village to raise a stylesheet
SassConf: It takes a village to raise a stylesheetSassConf: It takes a village to raise a stylesheet
SassConf: It takes a village to raise a stylesheet
 
Front-end development automation with Grunt
Front-end development automation with GruntFront-end development automation with Grunt
Front-end development automation with Grunt
 
Scaling PHP to 40 Million Uniques
Scaling PHP to 40 Million UniquesScaling PHP to 40 Million Uniques
Scaling PHP to 40 Million Uniques
 
Intro to pattern matching in scala
Intro to pattern matching in scalaIntro to pattern matching in scala
Intro to pattern matching in scala
 
Oxente on Rails 2009
Oxente on Rails 2009Oxente on Rails 2009
Oxente on Rails 2009
 
The Shape of Functional Programming
The Shape of Functional ProgrammingThe Shape of Functional Programming
The Shape of Functional Programming
 
Cooking an Omelette with Chef
Cooking an Omelette with ChefCooking an Omelette with Chef
Cooking an Omelette with Chef
 
Basics of Metaprogramming in Ruby
Basics of Metaprogramming in RubyBasics of Metaprogramming in Ruby
Basics of Metaprogramming in Ruby
 
Ruby 入門 第一次就上手
Ruby 入門 第一次就上手Ruby 入門 第一次就上手
Ruby 入門 第一次就上手
 
Introducing Modern Perl
Introducing Modern PerlIntroducing Modern Perl
Introducing Modern Perl
 
Pgbr 2013 postgres on aws
Pgbr 2013   postgres on awsPgbr 2013   postgres on aws
Pgbr 2013 postgres on aws
 
Regex Considered Harmful: Use Rosie Pattern Language Instead
Regex Considered Harmful: Use Rosie Pattern Language InsteadRegex Considered Harmful: Use Rosie Pattern Language Instead
Regex Considered Harmful: Use Rosie Pattern Language Instead
 
APMG juni 2014 - Regular Expression
APMG juni 2014 - Regular ExpressionAPMG juni 2014 - Regular Expression
APMG juni 2014 - Regular Expression
 

Dernier

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 

Dernier (20)

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 

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

  • 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. RUBY 2.0: A FEW COOL BITS Friday, August 9, 13
  • 3. #to_h hash representation, like to_a or to_s or to_sym. Friday, August 9, 13
  • 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. 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. 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. 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. 2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 } #bsearch Friday, August 9, 13
  • 11. 2.0.0p195 :003 > arr.bsearch{ |elem| p (n = n+1); elem == 11 } 1 2 3 => 11 #bsearch Friday, August 9, 13
  • 13. Undefined behavior if your Array is not sorted! Friday, August 9, 13
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. KEYWORD ARGUMENTS def my_method(arg1: ‘foo’, arg2: 123) p arg1 p arg2 end my_method “foo” 123 => 123 Friday, August 9, 13
  • 29. KEYWORD ARGUMENTS def my_method(arg1: ‘foo’, arg2: 123) p arg1 p arg2 end my_method “foo” 123 => 123 Friday, August 9, 13
  • 31. THOSE ARGS ARE NOT A HASH! Friday, August 9, 13
  • 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. 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. MODULE#PREPEND •I didn’t have time to write this slide! •But the feature is awesome, I promise! Friday, August 9, 13
  • 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. 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. 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. 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. 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. 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
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. PSST... A SECRET: You can do this in Rails 3, too. Just write your own smart cache key helpers. Friday, August 9, 13
  • 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. 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. ACTIVEMODEL::MODEL Helps to break the tendency to equate “resource” with “ActiveRecord Model.” Friday, August 9, 13
  • 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. 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. 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. 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. 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. 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. ACTIVEMODEL::MODEL # /app/views/users/_form = form_for(@user_form_model) = f.input(:name) = f.check_box(:admin) = f.submit! Friday, August 9, 13
  • 73. ‘cause that’s probably the right tool, really. Friday, August 9, 13
  • 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. 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. 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. 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. 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. ANY TIME LEFT? (IF SO, I’LL DO MODULE#PREPEND ON A WHITEBOARD OR SOMETHING.) Friday, August 9, 13
  • 81. Thanks! Evan Dorn Founder, Logical Reality Design http://lrdesign.com evan@lrdesign.com @idahoev Friday, August 9, 13