3つのモデル:ユーザー、映画、いいね
User has_many :likes
User has_many :movies, through: :likes
このコード:
user.movies = [ m1, m2, m3 ]
ユーザーとm1/m2/m3に関連Like#after_create
する新しいレコードを要求します。Like
次に、このコード:
user.movies = [ m3, m4 ]
ユーザーをm1/m2に関連付けるレコードは必要ありませんがLike#after_destroy
、m4との新しい関係は必要です。Like
Like#after_create
movies
コレクションは、手動で設定することも、user[movie_ids]
チェックボックスのあるフォームを使用して設定することもできます。
user.update_attributes(params[:user])
- コレクションを設定するための正しいRailsアプローチは何ですか?
- after_destroyを強制的に呼び出すにはどうすればよいですか?
アップデート:
@jdoeがドキュメントから引用しているように、新しいコレクションを割り当てるとき、またはコレクションから削除するときは達成できません(user.movies.delete(m1)
)。唯一の方法は、ユーザーモデル(およびポリモーフィック関係の場合は他のモデル)でbefore_remove
/コールバックを使用することです。定義は次のとおりです。after_remove
has_many
has_many :movies, through: :likes, before_remove: :before_like_destroy, after_remove: after_like_destroy
def before_like_destroy(movie)
like = self.likes.where(movie_id: movie)
# trigger the after_destroy on like
like.trigger_before_destroy # to be implemented on like, should call what the original callbacks contained
end
def after_like_destroy(movie)
# no way to get Like object here because it was already removed, need to remember it on the before_destroy somehow
end
その背後にある論理を理解することはできません。リレーションシップモデルのコールバックはまったく役に立たなくなります。何かが起こった場合、after_create
で元に戻すことはできませんafter_destroy
。また、ロジックの前後を別々にではなく一緒に使用することをお勧めします。これにより、すべてのコールバックが役に立たなくなります。
それを自動的に行う宝石を書くつもりだと思います。