ActiveRecord 如何调用 'where'?

How ActiveRecord calls 'where'?

你能告诉我 Active Record 在我执行 User.where(id: 1) 时如何调用 'where' 吗?

我正在检查 Active Record 的功能以读取源代码并通过 pry 停止进程。 我可以看到当我执行 User.where(id: 1) 时,过程转到 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' 委托给 :all。 因此它去 rails/activerecord/lib/active_record/scoping/named.rb

def all
  if current_scope
   current_scope.clone
  else
    default_scoped
  end
end

这部分我没看懂。为什么它适用于所有人? 委托可以设置为class方法吗?我虽然可以委托给class变量,实例变量。

在scoping/named.rb all方法中default_scope之后,流程进入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

为什么? where不是委托给:all吗?它如何回到 where(relation/query_methods.rb)?

I don't understand this part. Why it goes to all?

因为:

User.where(id: 1)

相当于:

User.all.where(id: 1)

此委托是为了简化 API,方法是在显式进行 none 时添加对 all 的隐式调用。

How does it get back to where (relation/query_methods.rb)?

请记住,这是委派,而不是别名。所以,因为:

User.all

returns:

User.default_scoped

这意味着,实际上,这是正在构建的方法链:

User.where
--> User.all.where
--> User.default_scoped.where

而由于User.default_scoped是一个User::ActiveRecord_Relation对象,它对#where的定义确实是在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

...但这只是故事的开始。我们距离构建查询的实际 SQL 还差得很远。

Here is a series of blog posts 如果您有兴趣,可以深入了解 - 但我认为这超出了单个 Whosebug 答案的范围。