概要
RegularEventにてhas_many :organizersを定義しているが、同名のdef organizersが定義されているため、ActiveRecordの関連メソッドを上書きしている状態になっている
- 意図的に上書きをしているかどうかは当時のコミットメッセージから読み取れず
- 現状、
regular_event.organizersはOrganizerではなくUserを返している
class RegularEvent < ApplicationRecord # rubocop:disable Metrics/ClassLength
has_many :organizers, dependent: :destroy
has_many :users, through: :organizers
def organizers
users.preload(avatar_attachment: :blob).order('organizers.created_at')
end
end
発行されるSQLの違い
# メソッドの上書きあり(`organizers`と書くと`User`が引っ張られる)
bootcamp(dev):002> RegularEvent.last.organizers.to_sql
RegularEvent Load (1.0ms) SELECT "regular_events".* FROM "regular_events"
ORDER BY "regular_events"."id" DESC LIMIT 1 /*application='Bootcamp'*/
=> "SELECT "users".* FROM "users" INNER JOIN "organizers" ON "users"."id" = \"organizers\".\"user_id\"
WHERE \"organizers\".\"regular_event_id\" = 1004488906 ORDER BY organizers.created_at"
# メソッドの上書きなし(`organizers`と書くと`Organizer`が引っ張られる)
bootcamp(dev):004> RegularEvent.last.organizers.to_sql
RegularEvent Load (0.5ms) SELECT "regular_events".* FROM "regular_events"
ORDER BY "regular_events"."id" DESC LIMIT 1 /*application='Bootcamp'*/
=> "SELECT \"organizers\".* FROM \"organizers\" WHERE \"organizers\".\"regular_event_id\" = 1004488906"
問題点
- メソッド名と実体が一致しておらず読み手が混乱しやすい(
organizersなのにUserが返る)
regular_event.organizers.destroy_allなどを書いた場合、意図せずUserが削除されてしまう可能性がある
- また、現状
regular_event.usersでorganizersになっているUserを持って来れるが、別のUserとの関連モデルであるParticipation(参加者)もあるため、usersだとどちらを参照しているのかわかりづらい
期待される振る舞い
regular_event.organizersはOrganizerを返すようにしたい
- 主催者ユーザー一覧が必要なら別名にする(例:
organizer_users)
- 別名の
has_manyアソシエーションを作り必要な情報を引っ張って来れるようにする
- scopeで定義でも良い?
- 不要になったコードは削除する
対応内容
概要
RegularEventにてhas_many :organizersを定義しているが、同名のdef organizersが定義されているため、ActiveRecordの関連メソッドを上書きしている状態になっているregular_event.organizersはOrganizerではなくUserを返している発行されるSQLの違い
問題点
organizersなのにUserが返る)regular_event.organizers.destroy_allなどを書いた場合、意図せずUserが削除されてしまう可能性があるregular_event.usersでorganizersになっているUserを持って来れるが、別のUserとの関連モデルであるParticipation(参加者)もあるため、usersだとどちらを参照しているのかわかりづらい期待される振る舞い
regular_event.organizersはOrganizerを返すようにしたいorganizer_users)has_manyアソシエーションを作り必要な情報を引っ張って来れるようにする対応内容
OrganizerモデルをRegularEventOrganizerにリネームorganizersテーブルをregular_event_organizersに変更has_many/through)を修正scopeやorder句などクエリ内のテーブル参照を修正organizersメソッド内の参照テーブルを修正(互換性のためメソッドは維持)user_id単体)を削除