本文介绍了Rails 没有通过连接模型为 has_many 运行销毁回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have two AR models and a third has_many :through join model like this:

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

有时,用户会想要直接删除电影(而不直接破坏评级).但是,当我这样做时:

Occasionally, a user will want to drop a movie directly (without directly destroying the rating). However, when I do:

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

user.movie_ids = [1, 2]

评级的 after_destroy 回调不会被调用,尽管连接记录已被适当删除.如果我像这样修改我的用户模型:

the rating's after_destroy callback isn't called, although the join record is deleted appropriately. If I modify my user model like this:

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 再次尝试删除连接模型.

Everything works fine, but this is really ugly, and Rails then tries to delete the join model a second time.

我如何为这个关联使用 dependent: :destroy 策略,而不是 dependent: :delete ?

How can I use a dependent: :destroy strategy for this association, rather than dependent: :delete?

推荐答案

回答我自己的问题,因为这对 Google 来说很难,而且答案超级反直觉(虽然我不知道理想的界面是什么)).

Answering my own question, since this was difficult to Google, and the answer is super counter-intuitive (although I don't know what the ideal interface would be).

首先,这里详细描述了情况:https://github.com/rails/rails/issues/7618.然而,具体的答案被埋在了页面的一半左右,问题被关闭了(尽管它在当前的 Rails 版本中仍然是一个问题).

First, the situation is described thoroughly here: https://github.com/rails/rails/issues/7618. However, the specific answer is buried about halfway down the page, and the issue was closed (even though it is still an issue in current Rails versions).

您可以为这些类型的连接模型销毁指定 dependent: :destroy,方法是在 has_many :through 命令中添加选项,如下所示:

You can specify dependent: :destroy for these types of join model destructions, by adding the option to the has_many :through command, like this:

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

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

This is counter-intuitive because in normal cases, dependent: :destroy will destroy that specific association's object(s).

例如,如果我们在这里有 has_many :ratings,dependent: :destroy,那么当该用户被销毁时,该用户的所有评分都将被销毁.

For example, if we had has_many :ratings, dependent: :destroy here, all of a user's ratings would be destroyed when that user was destroyed.

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

We certainly don't want to destroy the specific movie objects here, because they may be in use by other users/ratings. However, Rails magically knows that we want to destroy the join record, not the association record, in this case.

这篇关于Rails 没有通过连接模型为 has_many 运行销毁回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 21:12