before_destroy未从update_attributes触发

时间:2022-12-18 01:19:08

I have a student that has many courses. In the student#update action and form, I accept a list of course_ids. When that list changes, I'd like to call a certain function. The code I have does get called if the update_attributes creates a course_student, but does not get called if the update_attributes destroys a course_student. Can I get this to fire, or do I have to detect the changes myself?

我有一个有很多课程的学生。在学生#news操作和表单中,我接受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 个解决方案

#1


7  

It turns out that this behavior is documented, right on the has_many method. From the API documentation:

事实证明,这种行为是在has_many方法上记录的。从API文档:

collection=objects Replaces the collections content by deleting and adding objects as appropriate. If the :through option is true callbacks in the join models are triggered except destroy callbacks, since deletion is direct.

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

I'm not sure what "since deletion is direct" means, but there we have it.

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

#2


1  

Accepts nested attributes requires a flag to trigger nested destroy. Atleast it did back when.

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

#3


1  

If you add dependent: :destroy, it will honour that. Note that if you are using has_many through:, one needs to add that option to both.

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

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

(I have used that in Rails 3, I bet it will work on Rails 4 too)

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

#4


1  

When a record is deleted using update/update_attributes, it fires delete method instead of destroy.

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

@student.update_attributes(params[:student])

Delete method skips callbacks and therefore after_create / before_destroy would not be called. Instead of this accepts_nested_attributes_for can be used which deletes the record and also support callbacks.

Delete方法会跳过回调,因此不会调用after_create / before_destroy。可以使用accepts_nested_attributes_for来删除记录并支持回调。

accepts_nested_attributes_for :courses, allow_destroy: true

accepts_nested_attributes_for:courses,allow_destroy:true

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

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

#5


0  

Should your CourseStudent specify belongs_to :student, :dependent => :destroy, it seems like a CourseStudent record would not be valid without a Student.

如果您的CourseStudent指定belongs_to:student,:dependent =>:destroy,则看起来如果没有学生,CourseStudent记录将无效。

Trying to follow the LH discussion I linked to above, and this one I'd also try moving the before_destroy callback in CourseStudent below the belongs_to. The linked example demonstrates how the order of callbacks matters with an after_create, perhaps the same applies to before_destroy. And of course, since you're using Edge Rails, I'd also try the RC, maybe there was a bug they fixed.

试图按照我上面链接的LH讨论,这个我也尝试在belongs_to下面的CourseStudent中移动before_destroy回调。链接的示例演示了回调的顺序如何与after_create相关,也许同样适用于before_destroy。当然,既然你正在使用Edge Rails,我也会尝试RC,也许他们修复了一个bug。

Failing those things, I'd try to make a really simple Rails app with two models that demonstrates the problem and post it to Rails' Lighthouse.

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

#6


0  

Wasn't able to leave a comment, so I'll just add an answer entry.

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

Just encountered the same bug. After hours of trying to figure this issue out and an hour of google-ing, I stumbled to this question by chance. Along with the linked LH ticket, and quote from the API, it now makes sense. Thank you!

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

While googling, found an old ticket. Direct link does not work, but google cache has a copy. Just check Google for cached version of dev.rubyonrails.org/ticket/7743

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

Seems like a patch never made it to Rails.

看起来像一个补丁从未进入Rails。

#1


7  

It turns out that this behavior is documented, right on the has_many method. From the API documentation:

事实证明,这种行为是在has_many方法上记录的。从API文档:

collection=objects Replaces the collections content by deleting and adding objects as appropriate. If the :through option is true callbacks in the join models are triggered except destroy callbacks, since deletion is direct.

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

I'm not sure what "since deletion is direct" means, but there we have it.

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

#2


1  

Accepts nested attributes requires a flag to trigger nested destroy. Atleast it did back when.

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

#3


1  

If you add dependent: :destroy, it will honour that. Note that if you are using has_many through:, one needs to add that option to both.

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

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

(I have used that in Rails 3, I bet it will work on Rails 4 too)

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

#4


1  

When a record is deleted using update/update_attributes, it fires delete method instead of destroy.

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

@student.update_attributes(params[:student])

Delete method skips callbacks and therefore after_create / before_destroy would not be called. Instead of this accepts_nested_attributes_for can be used which deletes the record and also support callbacks.

Delete方法会跳过回调,因此不会调用after_create / before_destroy。可以使用accepts_nested_attributes_for来删除记录并支持回调。

accepts_nested_attributes_for :courses, allow_destroy: true

accepts_nested_attributes_for:courses,allow_destroy:true

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

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

#5


0  

Should your CourseStudent specify belongs_to :student, :dependent => :destroy, it seems like a CourseStudent record would not be valid without a Student.

如果您的CourseStudent指定belongs_to:student,:dependent =>:destroy,则看起来如果没有学生,CourseStudent记录将无效。

Trying to follow the LH discussion I linked to above, and this one I'd also try moving the before_destroy callback in CourseStudent below the belongs_to. The linked example demonstrates how the order of callbacks matters with an after_create, perhaps the same applies to before_destroy. And of course, since you're using Edge Rails, I'd also try the RC, maybe there was a bug they fixed.

试图按照我上面链接的LH讨论,这个我也尝试在belongs_to下面的CourseStudent中移动before_destroy回调。链接的示例演示了回调的顺序如何与after_create相关,也许同样适用于before_destroy。当然,既然你正在使用Edge Rails,我也会尝试RC,也许他们修复了一个bug。

Failing those things, I'd try to make a really simple Rails app with two models that demonstrates the problem and post it to Rails' Lighthouse.

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

#6


0  

Wasn't able to leave a comment, so I'll just add an answer entry.

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

Just encountered the same bug. After hours of trying to figure this issue out and an hour of google-ing, I stumbled to this question by chance. Along with the linked LH ticket, and quote from the API, it now makes sense. Thank you!

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

While googling, found an old ticket. Direct link does not work, but google cache has a copy. Just check Google for cached version of dev.rubyonrails.org/ticket/7743

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

Seems like a patch never made it to Rails.

看起来像一个补丁从未进入Rails。