Rails 6.1: 孤立化したレコードのリストを取れるmissing
クエリメソッドが追加(翻訳)
Rails 6.1に、ActiveRecord
内の孤立化したレコード(orphan record)を検索できるmissing
というクエリメソッドが追加されました( #34727)。
クリーンアップや一括アップデートなどのために、ActiveRecord
モデルに孤立レコードがあるかどうかをチェックするクエリを書くことがよくあります。
例
以下の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 6.1より前
担当管理職(manager)を参照できない求職リスト(job listing)をすべて検索するクエリを書いてみましょう。
[1] pry(main)> JobListing.left_joins(:manager).where(managers: {id: nil})
JobListing Load (0.2ms) SELECT "job_listings".* FROM "job_listings"
LEFT OUTER JOIN "managers" ON "managers"."id" = "job_listings"."manager_id"
WHERE "managers"."id" IS 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">]>
上の例ではleft_joins
を使っていますが、includes
やeager_load
でも同じことができます。
Rails 6.1以降
Rails 6.1のActiveRecord::QueryMethods::WhereChain
クラスにmissing
クエリメソッドが追加されました( #34727)。
missing
は、外部キーを参照できなくなっているレコードを検出するために、親子モデル間のLEFT OUTER JOINとWHERE句を含むリレーション(ActiveRecord::Relation)を返します。
上の例と同様に、担当管理職を参照できない求職リストをすべて検索してみましょう。
[1] pry(main)> JobListing.where.missing(:manager)
JobListing Load (0.1ms) SELECT "job_listings".* FROM "job_listings"
LEFT OUTER JOIN "managers" ON "managers"."id" = "job_listings"."manager_id"
WHERE "managers"."id" IS 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)>
メソッドにリレーション名を複数渡せば、複数のリレーションを組み合わせることもできます。
たとえば、担当管理職も求職への応募(job application)も参照できない求職リストを検索してみましょう。
[1] pry(main)> JobListing.where.missing(:manager, :job_applications)
JobListing Load (0.1ms) SELECT "job_listings".* FROM "job_listings"
LEFT OUTER JOIN "managers" ON "managers"."id" = "job_listings"."manager_id"
LEFT OUTER JOIN "job_applications" ON "job_applications"."job_listing_id" = "job_listings"."id"
WHERE "managers"."id" IS NULL AND "job_applications"."id" IS NULL LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>
[2] pry(main)>
上のコード例は、担当管理職を参照できない求職リストがある場合でも、求職リストから応募を参照できるので、空のリレーション(#<ActiveRecord::Relation []>
)を1件返します。
このコードは、担当管理職も応募も参照できない求職リストを識別します。
概要
原著者の許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
以下の関連記事もどうぞ。
missing
メソッド