before_destroy未从update_attributes触发

时间:2010-08-22 17:27:09

标签: ruby-on-rails collections associations callback

我有一个有很多课程的学生。在学生#upcate动作和表单中,我接受course_ids列表。当该列表发生变化时,我想调用某个函数。如果update_attributes创建了course_student,则会调用我的代码,但如果update_attributes销毁了course_student,则不会被调用。我可以解决这个问题,还是我必须自己检测这些更改?

# app/models/student.rb
class Student < ActiveRecord::Base
  belongs_to :teacher
  has_many :grades
  has_many :course_students, :dependent => :destroy
  has_many :courses, :through => :course_students
  has_many :course_efforts, :through => :course_efforts

  # Uncommenting this line has no effect:
  #accepts_nested_attributes_for :course_students, :allow_destroy => true

  #attr_accessible :first_name, :last_name, :email, :course_students_attributes

  validates_presence_of :first_name, :last_name
...
end

# app/models/course_student.rb
class CourseStudent < ActiveRecord::Base
  after_create  :reseed_queues
  before_destroy :reseed_queues

  belongs_to :course
  belongs_to :student

  private

  def reseed_queues
    logger.debug "******** attempting to reseed queues"
    self.course.course_efforts.each do |ce|
      ce.reseed
    end
  end

end

# app/controllers/students_controller.rb

  def update
    params[:student][:course_ids] ||= []
    respond_to do |format|
      if @student.update_attributes(params[:student])
        format.html { redirect_to(@student, :notice => 'Student was successfully updated.') }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @student.errors, :status => :unprocessable_entity }
      end
    end
  end

6 个答案:

答案 0 :(得分:7)

事实证明,此行为已记录在 has_many 方法上。从API文档:

  

<强>集合=对象      通过适当删除和添加对象来替换集合内容。如果:through选项为true,则连接模型中的回调将被触发,但destroy回调除外,因为删除是直接的。

我不确定“因为删除是直接的”意味着什么,但我们有它。

答案 1 :(得分:1)

接受嵌套属性需要一个标志来触发嵌套销毁。至少它确实回来了。

答案 2 :(得分:1)

如果你添加dependent: :destroy,它就会尊重这一点。请注意,如果您使用has_many through:,则需要将该选项添加到两者。

  has_many :direct_associations, dependent: :destroy, autosave: true
  has_many :indirect_associations, through: :direct_associations, dependent: :destroy

(我在Rails 3中使用过它,我敢打赌它也适用于Rails 4)

答案 3 :(得分:1)

使用update / update_attributes删除记录时,会触发delete方法,而不是destroy

@student.update_attributes(params[:student])

Delete方法skips回调,因此不会调用after_create / before_destroy。 可以使用删除记录并支持回调的accepts_nested_attributes_for代替。{/ p>

accepts_nested_attributes_for :courses, allow_destroy: true

@student.update_attributes(courses_attributes: [ {id: student_course_association_id, _destroy: 1 } ])

答案 4 :(得分:0)

如果您的CourseStudent指定belongs_to :student, :dependent => :destroy,那么没有学生,似乎CourseStudent记录无效。

尝试按照上面链接的LH讨论进行操作,并this one我还尝试在before_destroy下面的CourseStudent中移动belongs_to回调。链接的示例演示了回调的顺序如何与after_create重要,可能同样适用于before_destroy。当然,既然你正在使用Edge Rails,我也会尝试RC,也许他们修复了一个错误。

如果没有这些东西,我会尝试制作一个非常简单的Rails应用程序,其中有两个模型可以演示问题并将其发布到Rails的灯塔。

答案 5 :(得分:0)

无法发表评论,所以我只想添加一个答案条目。

刚遇到同样的错误。经过几个小时的尝试来解决这个问题和一个小时的谷歌,我偶然发现了这个问题。除了链接的LH票证,以及来自API的引用,它现在也是有意义的。谢谢!

谷歌搜索时发现了一张旧票。直接链接不起作用,但谷歌缓存有副本。 只需查看Google的dev.rubyonrails.org/ticket/7743缓存版

即可

似乎补丁从未进入Rails。