我们的User类上有一个default_scope
,它将用户限制为一组公司:
class User < ActiveRecord::Base
default_scope do
c_ids = Authorization.current_company_ids
includes(:companies).where(companies: { id: c_ids })
end
has_many :company_users
has_many :companies, through: company_users
end
class CompanyUser < ActiveRecord::Base
belongs_to :user
belongs_to :company
validates_uniqueness_of :company_id, scope: :user_id
end
class Company < ActiveRecord::Base
has_many :company_users
has_many :users, through: company_users
end
调用User.last
或User.find_by_email('mhayes@widgetworks.com')
或User.find(55557)
所有工作和作用域都符合预期。
调用User.exists?(id)
会抛出一个奇怪的错误:
Mysql2::Error: Unknown column 'companies.id' in 'where clause': SELECT 1 AS one FROM `users` WHERE `companies`.`id` IN (4) AND `users`.`id` = 55557 LIMIT 1
基本上,如果我得到这个,就意味着companies
不是User
上的列,事实确实如此。如果我甚至将sql复制到where
语句中,它的计算结果就会正确。
User.where("SELECT 1 AS one FROM `users` WHERE `companies`.`id` IN (4) AND `users`.`id` = 66668 LIMIT 1")
这让我认为default_scope
有一个求值顺序,exists?
在default_scope
之前被调用。
如果我打电话:
User.includes(:companies).where(companies: { id: [4] }).exists?(55557)
工作。这就是default_scope
正在做的,所以我知道default_scope
作用域没有失败。
我真的不知道,但在我看来,exists?
直接构建了一个关系,并决定抛出includes
子句,因为exists?
决定不需要加载其他对象。这种情况发生在这个方法调用中。而链式exists?
已经通过构建早期的关系(其中includes
被转换为joins
)正确地计算了它。
也许不是一个bug,但可能是default_scope
添加到列表中的另一个奇怪之处。
最好的解决方案可能是将default_scope
中的includes
变成实际的joins
,并在实际需要完整记录时手动调用includes
。(由于exists?
呼叫实际上并不需要它们)
另一种可能性是在CCD_ 28中仅将CCD_ 26和CCD_。我不知道这对arel
的计算有什么影响,尽管我有很多疑问可能不起作用
或者,如果你真的想让它总体保持不变,你可以做一些疯狂的事情,比如:
def self.exists?(args)
self.scoped.exists?(args)
end
它基本上会用默认作用域构建一个关系,然后在已经执行includes
->joins
魔术的已构建关联上调用exists?
。
试试这个
User.exists?(id: 55557)