Rails determine if objects from accepts_nested_attributes_for objects changed?
I am aware of the basic dirty indicator methods for rails, which work if direct attributes of an object have changed, I'm wondering how to determine if my children were updated..
I have a form for a collection of files, we'll call it a folder. A folder accepts_nested_attributes_for :files. What I need to determine (within the controller action) is whether or not the files that are within the params hash are different from the ones that are in the db.. So, did the user delete one of the files, did they add a 开发者_如何学Pythonnew file, or both (delete one file, and add another)
I need to determine this because I need to redirect the user to a different action if they deleted a file, versus adding a new file, versus just updated attributes of the folder.
def update
@folder = Folder.find(params[:id])
@folder.attributes = params[:folder]
add_new_file = false
delete_file = false
@folder.files.each do |file|
add_new_file = true if file.new_record?
delete_file = true if file.marked_for_destruction?
end
both = add_new_file && delete_file
if both
redirect_to "both_action"
elsif add_new_file
redirect_to "add_new_file_action"
elsif delete_file
redirect_to "delete_file_action"
else
redirect_to "folder_not_changed_action"
end
end
Sometimes you want to know that folder is changed without determining how. In that case you can use autosave
mode in your association:
class Folder < ActiveRecord::Base
has_many :files, :autosave => true
accepts_nested_attributes_for :files
attr_accessible :files_attributes
end
Then in controller you can use @folder.changed_for_autosave?
which returns whether or not this record has been changed in any way (new_record?, marked_for_destruction?, changed?), including whether any of its nested autosave associations are likewise changed.
Updated.
You can move model specific logic from controller to a method in folder
model, e.q. @folder.how_changed?
, which can return one of :add_new_file, :delete_file and etc. symbols (I agree with you that it's a better practice, I'd just tried to keep things simple). Then in controller you can keep logic pretty simple.
case @folder.how_changed?
when :both
redirect_to "both_action"
when :add_new_file
redirect_to "add_new_file_action"
when :delete_file
redirect_to "delete_file_action"
else
redirect_to "folder_not_changed_action"
end
This solution uses 2 methods: new_record?
and marked_for_destruction?
on each child model, because Rails in-box method changed_for_autosave?
can tell only that children were changed without how. This is just the way how to use this indicators to achieve your goal.
精彩评论