【问题标题】:Rails has_many using association ids not calling callback on destroyRails has_many 使用关联 ID 不会在销毁时调用回调
【发布时间】:2017-02-21 14:22:45
【问题描述】:

has_many 关系更新并销毁记录时,不会触发 after_commit 回调。

我有关系

class Expertise
  has_many :doctor_expertises
  has_many :doctor_profiles, through: :doctor_expertises

class DoctorExpertise
  belongs_to :doctor_profile
  belongs_to :expertise

  after_commit :do_something

  def do_something
     # not called when record destroyed 
  end

在我的控制器中,我使用以下方法更新has_many 关系

  def create
    doc = DoctorProfile.find(params[:doctor_id])
    doc.expertise_ids = params[:expertise_ids].select do |x|
      x.to_i > 0
    end
    doc.save!

    render json: doc.expertises
  end

我知道我应该在关系上使用updatedestroy。但是,为什么 after_commit 在记录被销毁时没有被调用?

我猜这与我设置doc.expertise_ids 不触发回调的方式有关。但是,除了简短的here 之外,我找不到有关此方法的任何文档。是否有文件证实或否认这种怀疑,或者还有其他事情发生?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    来自您链接的 RailsGuides:

    连接模型的自动删除是直接的,不会触发销毁回调。

    虽然它没有说明 after_commit 它很可能也没有被解雇

    我想你正在寻找的答案在这里:

    Howto use callbacks in a has_many through association?

    您需要在 has_many 声明中使用 after_remove

    【讨论】:

      【解决方案2】:

      更新加入模型关联,Rails 添加和删除集合上的记录。要删除记录,Rails 使用delete 方法,这个方法不会调用任何destroy callback

      解决方案 1

      在添加或删除关联时调用某些回调的一种方法是使用Association Callbacks

      class Expertise
        has_many :doctor_expertises
        has_many :doctor_profiles, through: :doctor_expertises
                 before_remove: :my_before_remove,
                 after_remove: my_after_remove           
      
        def my_before_remove(doctor_profile)
          ...
        end
      
        def my_after_remove(doctor_profile)
          ...
        end
      end
      

      解决方案 2

      在删除记录时,强制 Rails 调用 destroy 而不是 delete。 为此,请安装 gem replace_with_destroy 并将选项 replace_with_destroy: true 传递给 has_many 关联。

      class Expertise
        has_many :doctor_expertises
        has_many :doctor_profiles, through: :doctor_expertises,
                  replace_with_destroy: true        
        ...
      end
      
      class DoctorExpertise
        belongs_to :doctor_profile
        belongs_to :expertise
      
        after_commit :do_something
      
        def do_something
           # this will be called when updating Expertise.doctor_profiles
           # because use destroyed instead delete to remove the record
        end
      

      这样,您可以确保 Rails 调用所有 destroy callbacks

      【讨论】:

        【解决方案3】:

        只需像这样添加dependent: :destroy

        has_many :doctor_profiles, through: :doctor_expertises, dependent: :destroy

        我知道通过 has_many 依赖destroy有点误导,但它会触发destroy回调并且它不会破坏基本记录,只会破坏连接记录。参考:https://github.com/collectiveidea/audited/issues/246

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-09
          • 2015-06-01
          • 2010-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多