Reputation: 1832
I am having some issues when trying to skip a default_scope
when doing an ActiveRecord join
.
Even though the codebase is quite large, I am just showing the basics as I think it shows pretty well what the problem is:
class Client
belongs_to :company
end
class Company
default_scope { where(version_id: nil) }
end
I am building a complex report, so I need to join multiple tables and filter on them. However, I can't successfully skip the default scope when fetching Client
s.
Client.joins(:company).to_sql
# SELECT clients.* FROM clients INNER JOIN companies
# ON companies.id = clients.company_id AND companies.version_id IS NULL
As you can see that is automatically including the Company
default_scope
. So I tried this:
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
Again, I got the same result, even when using unscoped
with the block.
Then I decided to add a new association to the model, with the unscoped
scope:
class Client
belongs_to :company
belongs_to :unscoped_company, -> { unscoped }, foreign_key: :company_id, class_name: "Company"
end
Having added that, I gave another try:
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
And still the scoped is being applied.
Do you know how can I successfully join both tables without applying that default_scope
?
Removing that default_scope
is not an option as It is a big application and changing that will require too much time.
Rails v4.2.7
Ruby v2.2.3
Upvotes: 5
Views: 2315
Reputation: 11193
I did some research without finding any straight solution.
Here a couple of workarounds. I cannot say if they're going to work in your chained joins.
Client.joins("INNER JOINS companies ON companies.id = clients.company_id").to_sql
class CompanyUnscoped < Company
self.default_scopes = []
end
Don't forget to add this line to Client class:
belongs_to :company_unscoped, foreign_key: :company_id
Then you should be able to call
Client.joins(:company_unscoped)
#=> SELECT "clients".* FROM "clients" INNER JOIN "companies" ON "companies"."id" = "clients"."company_id"
Upvotes: 8
Reputation: 1402
Seems like there isn't any straightforward solution that you are looking for. There are couple of discussion threads for reference.
https://github.com/rails/rails/issues/20679
https://github.com/rails/rails/issues/20011
But I liked the way what @iGian has suggested.
Upvotes: 0
Reputation: 349
You might try https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-unscope but I would've expected https://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html#method-i-unscoped to work. You might try it again without a block, letting it come after the undesired scope is applied.
Upvotes: 0
Reputation: 1060
Apply directly as a class method
Client.unscoped.joins(:company).to_sql
Upvotes: 0
Reputation: 343
You can do it manually:
Client.joins('inner join company on companies.id = clients.company_id')
Upvotes: -1