- 更新日: 2015年10月17日
- Rails
Railsで複数テーブルのjoins/includesとwhere検索
Rails の ActiveRecord で複数の関連する DB テーブル(モデル)を joins/includes させて、where 検索を行う方法です。結構難しかった。
— 環境 —
Ruby 2.2.3
Rails 4.2.4
複数の関連するDBテーブル/モデルの例
以下のようなモデルのクラス群があるとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Country < ActiveRecord::Base has_many :prefectures end class Prefecture < ActiveRecord::Base belongs_to :country has_many :cities end class City < ActiveRecord::Base belongs_to :prefecture has_many :towns end class Town < ActiveRecord::Base belongs_to :city end |
以上のように「Country <- Prefecture <- City <- Town」というような関連になっている複数のモデルで、これらの複数の関連するDBテーブルを対象として、ActiveRecord の includes/joins を使って where 検索する方法です。
includes, joins で複数テーブルを where 検索
Town クラス(towns テーブル)に、City の名前(cities テーブルの name カラム)で検索する scope を作成してみます。同時に towns テーブルに、cities, prefectures, countries テーブルを joins/includes させる。
1 2 3 4 5 6 7 8 9 10 11 12 |
class Town < ActiveRecord::Base belongs_to :city # includes の場合は references(:cities) で where 句で参照するテーブル名を指定 scope :search_city, ->(name) { includes(city: [prefecture: [:country]]).where("cities.name = ?", name).references(:cities) } # joins の場合は references(:cities) は不要 # scope :search_city, ->(name) { joins(city: [prefecture: [:country]]).where("cities.name = ?", name) } end # 使う時 tokyo = Town.search_city('Tokyo') |
複数の関連テーブルを joins/includes する際には、親子関係となっている場合には、上記のようにシンボルを使ったハッシュ/配列を組み合わせて書きます。
親子関係じゃない並列の関係の場合は、配列の中に並べて書く。以下参考。
Railsで複数テーブルに跨ってincludesする – 飲んだり寝たり
また、実際の開発では N+1 問題の回避のために、joins ではなくて includes を使うことも多いかと思いますが、includes を使う場合は references メソッドに where 句で参照するテーブル名を指定します。
【追記 2015/10/17】
includes + references を使うと、SQL では LEFT OUTER JOIN が発行されます。場合によっては LEFT OUTER JOIN では都合が悪い場合もあるだろうから、INNER JOIN で eager loading する方法がないかを調べました。
結論から言いますと…
1 2 3 4 |
joins + preload # クエリ複数回 joins + eager_load # クエリ1回 |
を使うと可能なことが分かりました。この方法を使うと、INNER JOIN を使いつつ N+1 問題も回避できるはず。詳しくは以下を参照お願いします。
Rails – INNER JOIN で eager loading – Qiita
Rails – ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い – Qiita
Ruby – joinsを使ってeager loadingをする方法 – Qiita
【追記ここまで】
- – 参考リンク –
- references (ActiveRecord::QueryMethods) – APIdock
- Railsでアソシエーションされたモデルを条件にして検索する | Workabroad.jp
- Rails4 ActiveRecordのincludesで読み込んだ関連の値を利用するためにはreferencesメソッドが必要 – ayaketanのプログラミング勉強日記
- 【Ruby On Rails3】 複数のテーブルのincludesを書く! | approad
- Railsのfindメソッドのincludeオプションで、複数のテーブルをincludeする方法 – 久保清隆のブログ
- Rails4 3階層のincludesの複数指定 – ayaketanのプログラミング勉強日記
- Rails の関連記事
- RailsでMySQLパーティショニングのマイグレーション
- Rails ActiveRecordでdatetime型カラムのGROUP BY集計にタイムゾーンを考慮する
- RailsプラグインGemの作成方法、RSpecテストまで含めたrails pluginの作り方
- RailsでAMPに対応するgemをリリースしました
- Railsでrequest.urlとrequest.original_urlの違い
- Railsでwheneverによるcronバッチ処理
- Google AnalyticsのRails Turbolinks対応
- Railsアプリにソーシャル・シェアボタンを簡単設置
- Rails監視ツール用にErrbitをHerokuで運用
- Facebook APIバージョンのアップグレード手順(Rails OmniAuth)
- 初回公開日: 2015年10月16日
Leave Your Message!