Rails complex form editing multiple records at once with associations
I am developing a complex form that updates several records of one model at once, whilst simultaneously updating an associated model. It looks a bit like this:
class Sport
has_one :photo
end
class Photo
belongs_to :sport
acts_as_fleximage
end
class Page
# the page is not related to either of the previous models
end
Just for a bit of background info, the Page model is a generic model for which the users will be able to create as many as they like (a CMS). In addition, they are given a small number of compulsory "system" pages when they sign up. When they try to edit a system page, the form is slightly different from the generic page form.
One of the system pages is a "Sports" page. Where they can add some text for each of their sports (saved in the "sport" model) and upload a photo (saved in the "photo" model).
I've crafted a form which seems to be doing the trick. I won't post the view, but here is an example of the parameters it sends:
:id => 1
:page => {"title"=>"Our sports"}
:sport => {
"1" => {
"description" => "<p>I love playing hockey...</p>"
"photo_attributes" => {
"image_file" => #<File:/tmp/RackMultipart20100126-955-k0gxu8-0>,
"description" => "Me in my hockey kit"
}
},
"2" => { #more of the same}
}
Now, to save all this, my controller/action looks something like this:
def update_sports开发者_Python百科_page
@page = Page.find params[:id]
@page.update_attributes params[:page]
Sport.update(params[:sport].keys, params[:sport].values)
redirect_to #etc
end
Now when I edit the sports page, everything saves and updates correctly, EXCEPT, if I change the photo then rather than it updating the existing record in the database, it just creates a new record and sets the sport_id
of the old record to NULL
.
So eventually, after many edits, there is a huge number of orphan records in the database.
Can anyone spot what I am doing wrong here?
(ps, in case it's relevant, I'm using fleximage on the Photo model)
That's probably the correct behavior, since that association is set :dependent => :nullify by default, not :dependent => :destroy.
It might be possible to fix it with:
class Photo
belongs_to :sport,
:dependent => :destroy
end
That should remove orphan records automatically for you.
You should also be careful to catch exceptions when performing any find or update operation.
def update_sports_page
@page = Page.find params[:id]
@page.update_attributes params[:page]
params[:sport].each do |sport_id, sport_params|
sport = Sport.find(sport_id)
sport.update_attributes!(sport_params)
end
redirect_to #etc
rescue ActiveRecord::RecordNotFound
render(:partial => 'page_not_found', :status => :not_found)
rescue ActiveRecord::RecordInvalid
render(:action => 'edit')
end
That's an example. The edit and update method should have a common "sport loader" mechanism which can handle retrieving all the relevant records for the page instead of having to duplicate this functionality during update. It's responsible to catch errors on update and display them on the edit page for review.
精彩评论