Issue: Instead of updating nested attributes, they are being created on top of the existing nested attributes when I hit the #update
action of the associated features_controller.rb
Likely Cause: I think the problem lies in my lack of understanding in Rails' form_for
. I think the breakdown is in my views, how I render the persisting nested attributes, and/or how I fail to specify the nested attribute's id, causing it to simply create a new one
feature.rb
class Feature < ActiveRecord::Base ... has_many :scenarios accepts_nested_attributes_for :scenarios, allow_destroy: true, reject_if: :all_blank ... end
features_controller.rb
def update ... project = Project.find(params[:project_id]) @feature = Feature.find(params[:id]) if @feature.update_attributes(feature_params) # checking feature_params looks good... # feature_params['scenarios'] => { <correct object hash> } redirect_to project else render :edit end end ... private def feature_params params.require(:feature).permit(:title, :narrative, :price, :eta, scenarios_attributes[:description, :_destroy]) end
_form.html.haml (simplified)
= form_for [@project, @feature] do |f| ... - if @feature.new_record? -# if we are creating new feature = f.fields_for :scenarios, @feature.scenarios.build do |builder| = builder.label :description, "Scenario" = builder.text_area :description, rows: "3", autocomplete: "off" - else -# if we are editing an existing feature = f.fields_for :scenarios do |builder| = builder.label :description, "Scenario" = builder.text_area :description, rows: "3", autocomplete: "off"
I'm sure there's a nicer way to achieve the if @feature.new_record?
check. I'm also using a few Javascript hooks to create dynamic nested attribute forms (which I've left out), heavily influenced by Railscast #196 Nested Model Form (revised)
I would love a really nice Rails-y implementation of dealing with these sorts of nested forms.
Try adding :id
to the :scenario_attributes
portion of your feature_params
method. You only have the description field and the ability to allow a destroy.
def feature_params # added => before nested attributes params.require(:feature).permit(:id, :title, :narrative, :price, :eta, scenarios_attributes => [:id, :description, :_destroy]) end
As @vinodadhikary suggested, you no longer need to check if feature is a new record, since Rails, specifically using the form_for
method, will do that for you.
Update:
You don't need to define if @feature.new_record? ... else
in your form. It will be taken care by Rails when you use form_for
. Rails checks if the action is going to be create
or update
based on object.persisted?
, so, you can update your form to:
= form_for [@project, @feature] do |f| ... = f.fields_for :scenarios, @feature.scenarios.build do |builder| = builder.label :description, "Scenario" = builder.text_area :description, rows: "3", autocomplete: "off"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With