Rails 7: 関連付けのあるレコードを取れるassociated
クエリメソッドが追加(翻訳)
Rails 7で、ActiveRecord::Relation#missing
に似たassociated
というクエリメソッドが追加されました(#40696)。missing
は孤立化したオブジェクトのリストを取れるActiveRecord::Relation
を返すので、孤立化したオブジェクトが存在するかどうかをチェックできます。associated
は関連付けが存在するオブジェクトのリストを取れるActiveRecord::Relation
を返すので、関連付けのあるオブジェクトが存在するかどうかをチェックできます。
例
以下の3つのモデルで考えてみましょう。
# app/models/manager.rb
# Manager: 担当管理職
class Manager < ApplicationRecord
has_many :job_listings
end
# app/models/job_listing.rb
# JobListing: 求職リスト
class JobListing < ApplicationRecord
has_many :job_applications
belongs_to :manager
end
# app/models/job_application.rb
# JobApplication: 求職への応募
class JobApplication < ApplicationRecord
belongs_to :job_listing
end
Rails 7より前
担当管理職を参照できる求職リストをすべて検索するときは、以下のように行っていました。
[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">]>
Rails 7以後
Rails 7のActiveRecord::QueryMethods::WhereChain
クラスにassociated
クエリメソッドが追加されました(#40696)。
上述の例を用いて、担当管理職を参照可能な求職リストをすべて検索してみましょう。
[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)>
associated
は単なるシンタックスシュガーです。理由は、先の例と同様に存在チェックを行うINNER JOIN句とWHERE句を含むリレーション(ActiveRecord::Relation
)を返すからです。
associated
にはリレーション名を複数渡すことも可能です。
たとえば、担当管理職と応募のどちらも参照可能な求職リストを検索するには以下のようにします。
[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)>
このコード例では、担当管理職を参照可能な求職リストが存在する場合でも空のリレーション(#<ActiveRecord::Relation []>
)が返されました。理由は、この求職リストから参照できる応募が存在しなかったからです。
概要
原著者の許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。以下の関連記事もどうぞ。
追記(2021/09/27): 当初の原文はRails 6.1が対象となっていましたが、Rails 7が対象ではないかとのご指摘をいただき再確認したところ、原文もRails 7に修正されていたため、本記事も修正いたしました。ありがとうございます🙇