How do I update two models with one form in Ruby on Rails?
I have two models, Page and PageContent.
class Page < ActiveRecord::Base
has_many :page_contents
end
class PageContent < ActiveRecord::Base
belongs_to :page
end
Page has a :css_design attribute, but I want to be able to edit that attribute from my PageContent 开发者_开发技巧form. Any ideas?
I see a lot of accepts_nested_attributes and fields_for advice, but they don't work, because they all seem to be for forms that are either A. Creating entire new instances of a different model from a form (for example, creating tasks from a project form), or B. Updating associated records thru the parent. I want to do the opposite- I want to update the parent's record thru associated records.
Any help is greatly appreciated! Many thanks in advance!
--Mark
UPDATE
I have added the following to my PageContent model:
def css_design
page ? page.css_design : nil
end
def css_design= (val)
if page
page.update_attribute 'css_design', val
else
@css_design = val
end
end
after_create :set_page_css_design_on_create
def set_page_css_design_on_create
self.css_design = @css_design if page && @css_design
end
And I have, in both my create and update actions:
@page_content.update_attributes params[:page_content]
But I'm getting:
NoMethodError (undefined method `css_design=' for #<Page:0x00000003a80338>):
app/models/page_content.rb:13:in `css_design='
app/controllers/page_contents_controller.rb:56:in `new'
app/controllers/page_contents_controller.rb:56:in `create'
When I go to create the page_content for the first time. I copied and pasted this stuff straight from my files, so if you see anything weird, please let me know!
Update your model with the following:
class PageContent < ActiveRecord::Base
belongs_to :page
def css_design
page ? page.css_design : nil
end
def css_design= (val)
if page
page.update_attribute 'css_design', val
else
@css_design = val
end
end
after_create :set_page_css_design_on_create
def set_page_css_design_on_create
self.css_design = @css_design if page && @css_design
end
end
Your form can now display and update the current Page's value, even though it looks like it's only handling PageContent:
<%= form_for @page_content do |f| %>
...
<%= f.text_field :css_design %>
...
<% end %>
In your controller, e.g.:
def update
...
@page_content.update_attributes params[:page_content]
...
end
If it's not too many fields, you can add attributes to the PageContent model via attr_accessor. Then update the parent after_save. Something like this:
class PageContent < ActiveRecord::Base
belongs_to :page
attr_accessor :css_design
after_save :update_parent_css
private
def update_parent_css
self.page.update_attribute(:css_design, self.css_design)
end
end
Then you can put a form field for it just like any other PageContent field. If it's more than one field, use update_attributes. Also, you probably want to make sure the attribute is set (using attribute_present?(attribute)) so it doesn't overwrite it with nil.
(Sorry I don't have time to test it right away. I'll try later. )
精彩评论