今日はRailsで少し複雑なアソシエーションを組む方法について書いていこうと思います。アソシエーションを自在に組めるようになると、コードの見通しがすごくよくなるので自然と書けるようになりたいものです。
使用するサンプルアプリ
今回もユーザがイベントを開催でき、また参加できるアプリを例に書いていきます。ユーザは複数のイベントを開催でき、イベントは複数の参加するユーザを持てるので多対多の関係になります。そこで、中間テーブルとしてチケットテーブルを作っています。
アソシエーションを組んでみる
では実際にUserモデルにアソシエーションを定義していきます。
class User < ApplicationRecord
has_many :events, foreign_key: "owner_id"
has_many :tickets
has_many :events, through: :tickets
end
多対多のアソシエーションの場合、has_many: (中間テーブル)
とした上で、has_many :(多対多関連先のテーブル名)
としてthroughオプションで中間テーブルを指定します。
この際、中間テーブルのアソシエーションを前に書かないとエラーになるので気をつけてください。
しかし、これではuser.eventsとしたときに、名前の衝突が起きていて、開催するイベントなのか参加するイベントなのか分かりません。そこで、分かりやすい名前にアソシエーション名を変更します。
has_many :created_events, class_name: "Event", foreign_key: "owner_id"
has_many :participating_events, through: :tickets, source: event
まず、開催するイベントのアソシエーションをcreated_events
としました。これで、user.created_events
とたとき、開催するイベントを取得していることがひと目で分かります。ただし、関連名がモデル名ではなくなったため、どのモデルのものなのかをきちんと明示して上げる必要があります。そのときに使うオプションがclass_name
です。
1対多で関連先のモデル名を指定するオプションがclass_name
また、参加しているイベントのアソシエーションをparticipating_events
としました。これもuser.participating_events
としたとき、ユーザが開催しているイベントを取得していることが分かります。ここでも関連先のモデル名がRails側で分からないので、きちんと明示する必要があります。そのときに使うオプションがsourceです。先程のclass_name
と使い所は似てますが、こちらは多対多のときに使います。
多対多の関連先のモデル名を指定するオプションがsource
まとめ
このテクニックを使ってアソシエーションに分かりやすい名前をつけて、見通しのよいコードにしていきましょう。