1

I have

class Deal < ApplicationRecord
  belongs_to :company, dependent: :destroy
  accepts_nested_attributes_for :company

class DealsController < ApplicationController
  def update
    respond_to do |format|
      if @deal.update(deal_params)
        format.html { redirect_to dashboard_path, notice: 'Deal was successfully updated.' }
      ...

  def deal_params
    params.require(:deal).permit :name, ...
      company_attributes: [:name, ...]

When it submits the form, I see

  Parameters: {"utf8"=>"√", "deal"=>{"name"=>"Office building", ...
  "company_attributes"=>{"name"=>"...", "id"=>"25"}}, "commit"=>"Update Deal", "id"=>"1"}
Unpermitted parameter: id

But it always creates a new Company model instead of updating the existing associated model. I don't know why it's creating a new model. I don't include :id in company_attributes array because I'm afraid someone could use it to update something that doesn't belong to them.

Why is Rails always creating a new Company model instead of updating the existing Company model?

This question is similar but doesn't answer my question.

Rails 5.0.2


HTML requested:

<div class="form-group">
  <label for="deal_company_attributes_name">Name</label>
  <input class="form-control" type="text" value="West Side Offices LLC" name="deal[company_attributes][name]" id="deal_company_attributes_name">
</div>
...
<input type="hidden" value="26" name="deal[company_attributes][id]" id="deal_company_attributes_id">
<div class="actions">
  <input type="submit" name="commit" value="Update Deal" class="btn btn-primary" data-disable-with="Update Deal">
</div>
Community
  • 1
  • 1
Chloe
  • 25,162
  • 40
  • 190
  • 357

1 Answers1

2

But it always creates a new Company model instead of updating the existing associated model. I don't know why it's creating a new model.

For Update to work,you should include :id as well in the company_attributes. That is how StrongParameters deals with accepts_nested_attributes_for

In order to use accepts_nested_attributes_for with Strong Parameters, you will need to specify which nested attributes should be whitelisted. You might want to allow :id and :_destroy, see ActiveRecord::NestedAttributes for more information.

def deal_params
  params.require(:deal).permit :name, ...
      company_attributes: [:id, :name, ...]
end
Pavan
  • 33,316
  • 7
  • 50
  • 76
  • But can't a hacker modify the HTML form and change `id` to any random value to update a record that doesn't belong to them? Why does Rails need the `id` field anyways when it already knows the associated record from `@deal.company.id`? – Chloe May 11 '17 at 06:42
  • @Chloe Can you post the HTML of your form generated in the console? – Pavan May 11 '17 at 07:05
  • How is the HTML relevant? I showed the params submitted. Updated question. – Chloe May 11 '17 at 07:09
  • @Chloe It is relevant and it is **not safe** to put a `foreign_key` value as a **hidden field** in the form. There are better ways like adding it in the controller instead(see [*this*](http://stackoverflow.com/questions/31480645/how-to-add-foreign-key-value-on-controller-create)) – Pavan May 11 '17 at 07:19
  • Are you kidding me? That is how it's detailed in the [documentation](http://guides.rubyonrails.org/form_helpers.html#nested-forms)! And [#fields_for](http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-fields_for). – Chloe May 11 '17 at 07:25
  • I'm NOT! It is NOT safe to use hidden fields in forms. I hope [**this**](http://stackoverflow.com/questions/5163775/is-the-use-of-hidden-fields-in-forms-insecure) will give you a clear idea on why using the hidden fields in forms is insecure. – Pavan May 11 '17 at 07:35
  • Well then take it up with Rails, because that is what it generates. This is what prompted me to ask this question in the first place! – Chloe May 11 '17 at 07:43