Let me visualize that for you.
class Product < ActiveRecord::Base
end
Product.first.title
#=> "My sample product"
Nothing extraordinary here. Just a simple method call. Now take a look at the following example.
class Product < ActiveRecord::Base
def method_missing
end
end
Product.first.title
#=> nil
Product.first
Product.first.title
#=> "My sample product"
How is this possible? In some way they determine the end of the method chain and act upon that? At least thats my theory.
Can anyone explain this behavior?
You're seeing an artifact of using irb
to investigate things.
When you say this:
> Product.first.title
#=> nil
Your method_missing
will be called to lazy-load the title
method and you get nil
.
When you say this:
> Product.first
You're effectively doing this:
> p = Product.first; puts p.inspect
The first Product instance will be loaded and then irb
will call inspect
on it and AR will add the accessor methods along the way. The result is that Product will now have a title
method. Hence, doing this:
> Product.first
> Product.first.title
won't call your method_missing
at all as there will be a real title
method for Product.first.title
to call.
If you try again like this:
> Product.first; nil
> Product.first.title
You'll see two nil
s.
As far as chaining goes, ActiveRecord doesn't really detect the end, it is just that some method calls naturally require real data from the database and some don't.
If you call where
, order
, or any of the other querying methods, you get an ActiveRecord::Relation instance back and you can chain more query methods and scopes on that relation object. For example, where
(which ActiveRecord::Relation gets by including ActiveRecord::QueryMethods) looks like this:
def where(opts, *rest)
return self if opts.blank?
relation = clone
relation.where_values += build_where(opts, rest)
relation
end
so it just makes a copy of the current query, adds a few things to the copy, and gives you the copy back.
If you call first
, last
, to_a
, all
, any of the Enumerable methods (i.e. you call each
), ... then you're asking about specific instances and ActiveRecord will have to execute the query to realize the model instance(s) in question. For example, ActiveRecord::Relation#to_a
looks like this:
def to_a
logging_query_plan do
exec_queries
end
end
and all
is little more than a wrapper around to_a
.
ActiveRecord doesn't really know where the end of the chain is, it just doesn't load anything from the database until it has to so you tell it where the chain ends by saying go forth and retrieve me some data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With