ActiveRecord:与无作用域进行连接不会跳过default_scope

asc*_*man 4 ruby activerecord ruby-on-rails

default_scope我在尝试跳过 ActiveRecord 时遇到一些问题join

尽管代码库相当大,但我只是展示基础知识,因为我认为它很好地说明了问题所在:

class Client
  belongs_to :company
end

class Company
  default_scope { where(version_id: nil) }
end
Run Code Online (Sandbox Code Playgroud)

我正在构建一个复杂的报告,因此我需要连接多个表并对其进行过滤。但是,在获取 s 时我无法成功跳过默认范围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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它会自动包含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
Run Code Online (Sandbox Code Playgroud)

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

然后我决定向模型添加一个新的关联,其unscoped范围:

class Client
  belongs_to :company
  belongs_to :unscoped_company, -> { unscoped }, foreign_key: :company_id, class_name: "Company"
end
Run Code Online (Sandbox Code Playgroud)

添加后,我又尝试了一次:

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
Run Code Online (Sandbox Code Playgroud)

并且仍在应用范围。

您知道如何在不应用它的情况下成功连接两个表吗default_scope?删除它default_scope不是一个选择,因为它是一个大型应用程序,并且更改它需要太多时间。


导轨 v4.2.7

红宝石 v2.2.3

iGi*_*ian 7

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

这里有几个解决方法。我不能说它们是否会在您的链接连接中工作。


首先是基本操作,手动执行:
Client.joins("INNER JOINS companies ON companies.id = clients.company_id").to_sql
Run Code Online (Sandbox Code Playgroud)
其他选项定义一个继承自“Company”的“CompanyUnscoped”类,删除default_scope:
class CompanyUnscoped < Company

  self.default_scopes = []

end
Run Code Online (Sandbox Code Playgroud)

不要忘记将此行添加到 Client 类中:

belongs_to :company_unscoped, foreign_key: :company_id
Run Code Online (Sandbox Code Playgroud)

然后你应该可以打电话

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