Rails 7
adds
query method associated
similar to ActiveRecord::Relation#missing.
missing
checks for the orphan objects, while associated
checks for the association presence.
Example
Let us consider the following models.
# app/models/manager.rb
class Manager < ApplicationRecord
has_many :job_listings
end
# app/models/job_listing.rb
class JobListing < ApplicationRecord
has_many :job_applications
belongs_to :manager
end
# app/models/job_application.rb
class JobApplication < ApplicationRecord
belongs_to :job_listing
end
Before Rails 7
Now let us try to find all the job listings which have a manager assigned.
[1] pry(main)> JobListing.joins(:manager).where.not(managers: {id: nil})
JobListing Load (0.2ms) SELECT "job_listings".* FROM "job_listings"
INNER JOIN "managers" ON "managers"."id" = "job_listings"."manager_id"
WHERE "managers"."id" IS NOT NULL LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Manager id: 3, name: "Jane Doe", created_at: "2020-01-20 14:31:16", updated_at: "2020-01-20 14:31:16">]>
After Rails 7
Rails 7
adds
a query method associated
to the ActiveRecord::QueryMethods::WhereChain
class.
From the example above, let us find all the job listings which have a manager assigned.
[1] pry(main)> JobListing.where.associated(:manager)
JobListing Load (0.1ms) SELECT "job_listings".* FROM "job_listings"
INNER JOIN "managers" ON "managers"."id" = "job_listings"."manager_id"
WHERE "managers"."id" IS NOT NULL LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Manager id: 3, name: "Jane Doe", created_at: "2020-01-20 14:31:16", updated_at: "2020-01-20 14:31:16">]>
[2] pry(main)>
It is just syntactic sugar on top because it also returns a relation with inner join and where clause to check for the presence.
We can also pass multiple relation names to the method.
For example, to find job listings which are having both a manager and a job application:
[1] pry(main)> JobListing.where.associated(:manager, :job_applications)
JobListing Load (0.1ms) SELECT "job_listings".* FROM "job_listings"
INNER JOIN "managers" ON "managers"."id" = "job_listings"."manager_id"
INNER JOIN "job_applications" ON "job_applications"."job_listing_id" = "job_listings"."id"
WHERE "managers"."id" IS NOT NULL AND "job_applications"."id" IS NOT NULL LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>
[2] pry(main)>
In the example above, even though we have a job listing where a manager is assigned, an empty relation is returned because that job listing had no job applications.