Could you let me know how Active Record calls 'where' when I execute User.where(id: 1)
?
I'm checking Active Record's functionality to read the source code and stop the process by pry.
I can see when I execute User.where(id: 1)
, the process goes to
rails/activerecord/lib/active_record/querying.rb
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
:where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly,
:having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
'where' is delegated to :all.
Thus it goes to
rails/activerecord/lib/active_record/scoping/named.rb
def all
if current_scope
current_scope.clone
else
default_scoped
end
end
I don't understand this part. Why it goes to all? delegate can be set to class method? I though it can be delegated to class variables, instance variables.
after default_scope in scoping/named.rb all method, the process goes to rails/activerecord/lib/active_record/relation/query_methods.rb
def where(opts = :chain, *rest)
if :chain == opts
WhereChain.new(spawn)
elsif opts.blank?
self
else
spawn.where!(opts, *rest)
end
end
Why? Isn't where
delegated to :all
? How does it get back to where
(relation/query_methods.rb)?
I don't understand this part. Why it goes to
all
?
Because:
User.where(id: 1)
is equivalent to:
User.all.where(id: 1)
This delegation is to simplify the API, by adding an implicit call to all
when none is explicitly made.
How does it get back to
where
(relation/query_methods.rb)?
Remember that this was a delegation, not an alias. So, since:
User.all
returns:
User.default_scoped
This means that, effectively, this is the method chain being constructed:
User.where
--> User.all.where
--> User.default_scoped.where
And since User.default_scoped
is a User::ActiveRecord_Relation
object, its definition of #where
is indeed defined in rails/activerecord/lib/active_record/relation/query_methods.rb
, as:
def where(opts = :chain, *rest)
if :chain == opts
WhereChain.new(spawn)
elsif opts.blank?
self
else
spawn.where!(opts, *rest)
end
end
...But this is only the beginning of the story. We are still quite a way off constructing the actual SQL for the query.
Here is a series of blog posts that dive deeper, if you're interested - but I think this goes beyond the scope of a single StackOverflow answer.