带有命名空间模型的ActiveRecord WHERE



我在相同的命名空间/模块中有两个模型

module ReverseAuction
class Demand < ApplicationRecord
belongs_to :purchase_order, inverse_of: :demands, counter_cache: true
end
end
module ReverseAuction
class PurchaseOrder < ApplicationRecord
has_many :demands
end
end

请注意,我不必为模型指定class_name,因为它们在同一个模块中,并且关系以这种方式运行良好。

当我试图用关系的名称查询includes时,它工作得很好,比如:

ReverseAuction::PurchaseOrder.all.includes(:demands)  # all right .. AR is able to figure out that *:demands* correspond to the 'reverse_auction_demands' table

但是当我尝试在这个查询中使用where时,AR似乎无法自己计算出(按名称空间排列的(表名,所以:

ReverseAuction::PurchaseOrder.includes(:demands).where(demands: {user_id: 1}) # gives me error: 'ERROR: missing FROM-clause entry for table "demands"'

但是,如果我指定了完全解析(命名空间(的模型名称,那么其中很好:

ReverseAuction::PurchaseOrder.includes(:demands).where(reverse_auction_demands: {user_id: 1}) # works pretty well

AR可以中的关系中推断出名称空间模型的表名,但不能中这正常吗?还是我没有抓住要点?

AR可以从includes中的关系,但不能在

这是一个泄漏抽象的例子。

Assocations是一种围绕SQL连接的面向对象的抽象,让您可以在AR担心编写SQL来连接它们以及维护记录之间的内存耦合时做一些有趣的事情。.joins.left_joins.includes.eager_load是"0";意识到";你的联想,并通过抽象。因为有了这种面向对象的抽象,.includes足够聪明,可以在编写联接时弄清楚模块嵌套应该如何影响类名和表名。

.where和ActiveRecord查询接口的所有其他部分都不那么智能。这只是一个以编程方式生成SQL查询的API。当您执行.where(foo: 'bar')时,它足够聪明,可以将其转换为WHERE table_name.foo = 'bar',因为类知道自己的表名。

当您执行.where(demands: {user_id: 1})时,该方法实际上并不知道您的关联、其他模型类或模式,而只是生成WHERE demands.user_id = 1,因为这就是它将嵌套哈希转换为SQL的方式。

请注意,这实际上与名称空间无关。当你这样做:

.where(reverse_auction_demands: {user_id: 1})

它之所以有效,是因为您使用了正确的表名。如果使用与模型不一致的非常规表名,则会遇到完全相同的问题。

如果您想在不硬编码表名的情况下基于类创建where子句,请将作用域传递到where:

.where(
ReverseAuction::Demand.where(user_id: 1)
)

或使用Arel:

.where(
ReverseAuction::Demand.arel_table[:user_id].eq(1)
)

最新更新