ActiveRecord .exists?()和default_scope奇怪

时间:2015-04-13 19:57:14

标签: ruby-on-rails ruby-on-rails-3 activerecord exists default-scope

我们的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.lastUser.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上的列,而是where。如果我甚至将sql复制到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正在做的事情,所以我知道{{1}}范围没有失败。

2 个答案:

答案 0 :(得分:1)

老实说,我不知道,但我认为exists?直接构建 relation 并决定抛出includes子句,因为exists?决定它不需要加载其他对象。这发生在this method call。而链式 exists?已经通过构建早期的关系(其中includes转换为joins)正确计算了它

也许不是一个错误,但可能是另一个奇怪的事情,用default_scope添加到列表中。

最好的解决方案可能是将includes中的default_scope变为实际joins,并在实际需要完整记录时手动调用includes。 (因为exists?通话实际上并不需要它们)

另一种可能性是在includes中链接joinsdefault_scope。我不知道这对arel计算有什么影响,尽管我对此表示怀疑。 五月或五月不起作用。

或者如果你真的希望它保持整体相同,你可以做一些疯狂的事情:

def self.exists?(args)
  self.scoped.exists?(args)
end

这将基本上构建一个具有默认范围的 relation ,然后在已经执行exists?的已构建关系上调用includes - &gt ; joins魔法。

答案 1 :(得分:0)

试试这个

User.exists?(id: 55557)