Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails 6.1: 孤立化したレコードのリストを取れる'missing'クエリメソッドが追加(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。

以下の関連記事もどうぞ。

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を使っていますが、includeseager_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件返します。

このコードは、担当管理職も応募も参照できない求職リストを識別します。

関連記事

Rails 6.1: whereの関連付けでjoinedテーブルのエイリアス名を参照可能になった(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。