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。