Rails没有通过连接模型运行has_many的destroy回调

时间:2015-06-03 20:08:20

标签: ruby-on-rails ruby-on-rails-4 rails-activerecord

我有两个AR模型和第三个has_many :through连接模型,如下所示:

class User < ActiveRecord::Base
  has_many :ratings
  has_many :movies, through: :ratings
end

class Movie < ActiveRecord::Base
  has_many :ratings
  has_many :users, through: :ratings
end

class Rating < ActiveRecord::Base
  belongs_to :user
  belongs_to :movie

  after_destroy do
    puts 'destroyed'
  end    
end

有时,用户会想要直接放弃电影(不直接破坏评级)。但是,当我这样做时:

# puts user.movie_ids
# => [1,2,3]

user.movie_ids = [1, 2]

虽然正确删除了联接记录,但未调用评级的after_destroy回调。如果我像这样修改我的用户模型:

class User < ActiveRecord::Base
  has_many :ratings
  has_many :movies, 
    through: :ratings,
    before_remove: proc { |u, m| Rating.where(movie: m, user: u).destroy_all }
end

一切正常,但这真的很难看,然后Rails会再次尝试删除连接模型。

如何为此关联使用dependent: :destroy策略,而不是dependent: :delete

1 个答案:

答案 0 :(得分:11)

回答我自己的问题,因为这对谷歌来说很难,答案是超级直观的(虽然我不知道理想界面会是什么)。

首先,这里详细描述了这种情况:https://github.com/rails/rails/issues/7618。但是,具体的答案埋在页面的中间位置,问题已经关闭(即使它仍然是当前Rails版本中的一个问题)。

您可以通过向dependent: :destroy命令添加选项为这些类型的连接模型析构指定has_many :through,如下所示:

class User < ActiveRecord::Base
  has_many :ratings
  has_many :movies, 
    through: :ratings,
    dependent: :destroy
end

这是违反直觉的,因为在正常情况下,dependent: :destroy会破坏该特定关联的对象。

例如,如果我们在此处has_many :ratings, dependent: :destroy,那么当该用户被销毁时,所有用户的评级都将被销毁。

我们当然不想破坏这里的特定电影对象,因为它们可能被其他用户/评级使用。但是,在这种情况下,Rails神奇地知道我们想要破坏连接记录,而不是关联记录。