ActiveRecord:与无作用域的联接不会跳过default_scope

时间:2019-05-31 23:41:00

标签: ruby-on-rails ruby activerecord

在执行ActiveRecord default_scope时尝试跳过join时遇到一些问题。

即使代码库很大,我也只是展示基础知识,因为我认为它很好地说明了问题所在:

class Client
  belongs_to :company
end

class Company
  default_scope { where(version_id: nil) }
end

我正在构建一个复杂的报表,因此我需要连接多个表并对其进行过滤。但是,在获取Client时,我无法成功跳过默认范围。

Client.joins(:company).to_sql
# SELECT clients.* FROM clients INNER JOIN companies
# ON companies.id = clients.company_id AND companies.version_id IS NULL

如您所见,它会自动包含Company default_scope。所以我尝试了这个:

Company.unscoped { Client.joins(:company) }.to_sql
# SELECT clients.* FROM clients INNER JOIN companies
# ON companies.id = clients.company_id AND companies.version_id IS NULL

同样,即使将unscoped与该块一起使用,我也得到相同的结果。

然后,我决定使用unscoped范围向模型添加新的关联:

class Client
  belongs_to :company
  belongs_to :unscoped_company, -> { unscoped }, foreign_key: :company_id, class_name: "Company"
end

添加了这一点,我再次尝试:

Client.joins(:unscoped_company).to_sql
# SELECT clients.* FROM clients INNER JOIN companies
# ON companies.id = clients.company_id AND companies.version_id IS NULL

仍然应用了作用域。

您知道如何在不应用default_scope的情况下成功地联接两个表吗? 不能删除default_scope,因为这是一个很大的应用程序,因此更改将需要太多时间。


Rails v4.2.7

Ruby v2.2.3

5 个答案:

答案 0 :(得分:1)

似乎没有您想要的简单解决方案。有几个讨论线程可供参考。

https://github.com/rails/rails/issues/20679

https://github.com/rails/rails/issues/20011

但是我喜欢@iGian的建议。

答案 1 :(得分:0)

您可以手动执行:

i

答案 2 :(得分:0)

直接作为类方法应用

Client.unscoped.joins(:company).to_sql

答案 3 :(得分:0)

我做了一些研究,却没有找到直接的解决方案。

这里有两个解决方法。我不能说他们是否将在您的链式联接中工作。


首先,请手动进行:

Client.joins("INNER JOINS companies ON companies.id = clients.company_id).to_sql


其他选项定义一个CompanyUnscoped类,该类继承自Company,并删除了default_scope:

class CompanyUnscoped < Company

  self.default_scopes = []

end

别忘了将此行添加到Client类:

belongs_to :company_unscoped, foreign_key: :company_id

那你应该可以打电话

Client.joins(:company_unscoped)
#=> SELECT "clients".* FROM "clients" INNER JOIN "companies" ON "companies"."id" = "clients"."company_id"

答案 4 :(得分:0)

您可以尝试https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-unscope,但我希望https://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html#method-i-unscoped可以工作。您可以无障碍地再次尝试,让它在应用了不需要的作用域之后出现。