4

3 models: User, Movie, Like

User has_many :likes
User has_many :movies, through: :likes

This code:

user.movies = [ m1, m2, m3 ]

calls Like#after_create for the new Like records that relate user and m1/m2/m3. Then, this code:

user.movies = [ m3, m4 ]

doesn't call Like#after_destroy for the Like records that relate user to m1/m2, but does call Like#after_create for the new relationship with m4.

The movies collection could be set manually or with a form that has user[movie_ids] checkboxes, and then

user.update_attributes(params[:user])
  1. What is the right Rails approach for setting a collection?
  2. How do I force it to call after_destroy?

Update:

As @jdoe cited from the docs, it's not achievable when assigning new collection or when deleting from a collection (user.movies.delete(m1)). The only way is to use before_remove/after_remove callbacks on the user model (and in case of a polymorphic relationship -- any other model), with the has_many definition:

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

Can't understand the logic behind it. It makes callbacks on relationship models totally useless. If something happened on after_create it can't be undone in after_destroy, and since it's better practice to have after and before logic together and not separately, it makes all callbacks useless.

Think I'm gonna write a gem that does that automagically.

4

2 回答 2

3

根据文档:

集合=对象

通过酌情删除和添加对象来替换集合内容。如果 :through 选项为 true ,则连接模型中的回调会被触发,但销毁回调除外,因为删除是直接的。

于 2012-07-05T09:05:39.660 回答
0

如果你将dependent: :destroy 添加到like 和movie 关联中,它会调用after_destroy 回调

于 2014-11-13T18:41:13.210 回答