has_many: through で dependent: :destroy を付けないとafter_destroyが走らない
ref:
has_many: through についておさらい
n : n の関連付けを実装する手法の1つ(もう1個あるけど非推奨)
例
学生は部活を複数かけもちできるし、部活には複数の学生が属している
https://gyazo.com/8df64315c670c55eb3bc68184e7a6ffb
through を使って関連付けするとこうなる
code:.rb
# 学生class
class Student
has_many :stundent_clubs
has_many :clubs, through: :stundent_clubs
end
# 中間テーブル
class StudenClub
belongs_to :student
belongs_to :club
end
# 部活class
class Club
has_many :stundent_clubs
has_many :students, through: :stundent_clubs
end
本題:has_many thorouth の callback の挙動
code: .rb
# 学生class
class Student
has_many :stundent_clubs
has_many :clubs, through: :stundent_clubs
end
# 中間テーブル
class StudenClub
belongs_to :student
belongs_to :club
# ✅ コールバック追加
after_create :hogehoge
after_destroy :fugafuga
end
# 部活class
class Club
has_many :stundent_clubs
has_many :students, through: :stundent_clubs
end
after_createの動作
Student が新しくClubに加入する時 = StudentClunb.create!(student: some_student, club: some_club) が実行される時、after_createコールバックは正常にトリガーされて実行される
after_destroyの動作
StudentがClubから脱会する時 = StudentClub.destroy!(student: some_student, club: some_club) のような処理が実行されても、 after_destroy :fugafugaは走らない
理由: delete_allが実行されるから
code: .sql
StudenClub Delete All (xxx ms) DELETE FROM student_clubs WHERE student_clubs.user_id = 1 AND bookings.club_id = 2
deleteとdestroyの違い
destroy:データをインスタンス化して削除する。
delete:データをインスタンス化せずにSQLを直接実行して削除する。ActiveRecordを介さない。コールバックが働かないので業務処理には適していません(by 独習Rails p.188)
解決策: dependent: :destroy を付ける
code: .rb
# 学生class
class Student
has_many :stundent_clubs
has_many :clubs, through: :stundent_clubs, dependent: :destroy # 追加
end
# 中間テーブル
class StudenClub
belongs_to :student
belongs_to :club
after_create :hogehoge
after_destroy :fugafuga
end
# 部活class
class Club
has_many :stundent_clubs
has_many :students, through: :stundent_clubs, dependent: :destroy # 追加
end
Student classに dependent: :destroyを追加することで、StudentClub.destroy!時に StudenClubのインスタンスが destroyされるようになる
code: .sql
StudenClub Destroy (xxx ms) DELETE FROM student_clubs.id = 1