Railsで多対多の関連を実装する
参考記事
以下を参考にさせていただきました。
開発現場でちゃんと使えるRails 4入門(6):ActiveRecordにおけるモデルの「関連」とコールバックの使い方 (2/3) - @IT
Railsで多対多のモデルを簡単に扱えるhas_many :through - このブログは証明できない。
やり方
「多対多の関連」は中間モデルとhas_manyの:throughオプションで簡単に実装できる。
今回はUbernのようなアプリで、Userがどのドライバーをりようしたかということを記録したい、というシチュエーションで。UserモデルとDriverモデルはすでに作成済みの状態からいきます。
まずは関連情報を扱う中間モデルを作成
$ rails g model History user:references driver:references invoke active_record create db/migrate/20150318014312_create_histories.rb create app/models/history.rb invoke rspec create spec/models/history_spec.rb invoke factory_girl create spec/factories/histories.rb
dbに反映させます。
$ bundle exec rake db:migrate
referencesは実際にテーブルに格納された時にただのintegerになるのだけど、自動で関連を調べてカラムの名前をつけてくれるみたい。例えばUserクラスとDriverクラスのひもづけなら、user_idとdriver_idという名前を自動で振ってくれれてる。
そしたら各モデルのファイルに以下を加えます。
# app/models/user.rb has_many :histories has_many :drivers, through: :histories
# app/models/driver.rb has_many :histories has_many :users, through: :histories
両方がhas_manyの関係になってます。そしてthrough:
にすることで
ちなみに変則的な複数名詞への変換も、だいたいの単語はActiveSupportが対応してやってくれてるらしい。Railsってやっぱ巨大ですげぇ...
あとはこんな感じにするだけであるユーザにひも付けられているドライバーだけを全て取り出せます。すごい!
history_drivers = current_user.drivers
テストは以下のように書けばokです!
it { is_expected.to have_many(:drivers).through(:histories) }