exploring the magic behind dynamic finders: diving into activerecord::base.method_missing
Post on 13-Sep-2014
3.549 views
DESCRIPTION
An exploration of how dynamic finders work in ActiveRecord.TRANSCRIPT
![Page 1: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/1.jpg)
Exploring the Magic Behind
Dynamic Finders Diving into
ActiveRecord::Base.method_missing
![Page 2: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/2.jpg)
What are they?
address
last_name
first_name
id
people class Person < ActiveRecord::Base
end
![Page 3: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/3.jpg)
What are they?
address
last_name
first_name
id
people class Person < ActiveRecord::Base
end
Person.find_by_first_name 'mike'
Person.find_by_first_name_and_last_name 'mike', 'bowler'
Dynamic finder
![Page 4: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/4.jpg)
methods vs messages
Customer Object
first_name()
Message Method
Person
![Page 5: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/5.jpg)
messages without methods
Customer Object
search()
method_missing()
Message
Method
Person
![Page 6: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/6.jpg)
method_missing in rails
ActiveRecord::Base implements method_missing and dynamically adds support for the find_ methods
![Page 7: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/7.jpg)
Inside ActiveRecord::Base
def method_missing(method_id, *arguments) if match =~ /^find_(all_by|by)_([_a-zA-Z]\w*)$/ # ... elsif match =~ /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/ # ... else super endend
![Page 8: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/8.jpg)
find :all, :conditions => { :first_name => first_name, :last_name => last_name }
Person.find_all_by_first_name_and_last_name( ‘mike’, ‘bowler’)
def self.method_missing(method_id, *arguments) if method_id.to_s =~ /^find_all_by_([_a-zA-Z]\w*)$/ attribute_names = $1.split '_and_' conditions = {} attribute_names.each_with_index do |name, index| conditions[name.to_sym] = arguments[index] end find :all, :conditions => conditions else super endend
![Page 9: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/9.jpg)
Can we make this faster?
![Page 10: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/10.jpg)
Metaprogramming
Ruby’s metaprogramming allows us to dynamically create a new method
![Page 11: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/11.jpg)
def self.method_missing(method_id, *arguments) if method_id.to_s =~ /^find_all_by_([_a-zA-Z]\w*)$/ attribute_names = $1.split('_and_') conditions = attribute_names.collect {|name| ":#{name} => #{name}"}. join(', ')
class_eval <<-END def self.#{method_id} #{attribute_names.join ','} find(:all, :conditions => {#{conditions}}) puts "in method" end END __send__(method_id, *arguments) else super endend
def self.find_all_by_first_name_and_last_name first_name,last_name find(:all, :conditions => {:first_name => first_name, :last_name => last_name})end
![Page 12: Exploring the magic behind dynamic finders: diving into ActiveRecord::Base.method_missing](https://reader033.vdocuments.site/reader033/viewer/2022061104/54145ef88d7f72506c8b456a/html5/thumbnails/12.jpg)
Shameless Plug
I can help you with your Ruby and/or Rails projects. Ask me how.
Mike [email protected] (company)www.SphericalImprovement.com (blog)