Leeder
Leeder

Reputation: 77

Rails doesn't update nested attributes

I create an application, which is basically a character creator for an RPG with interactive and dynamic forms. I use Rails 5.0.0.1, and I cannot update my form properly. The base model updates well, but all nested don't.

So, I have

class Character < ApplicationRecord
  has_many :attr4characters, autosave: true
  accepts_nested_attributes_for :attr4characters, allow_destroy: true
end

and

class Attr4character < ApplicationRecord
  belongs_to :character
end

which represent a character and a set of his attributes. Each record in Attr4character is a different attribute.

The Show view is simple:

...
<div class="field">
  <%= f.label :description %>
  <%= f.text_area :description %>
</div>

<div class="field">
  <%= f.label :character_type %>
  <%= f.select(:character_type, options_for_select(["Zhong Lung", "Shih", "Hsien", "Garou", "Technocrat"])) %>
</div>

  <% f.object.attr4characters.each do |attr| %>
    <%= f.fields_for attr do |attr_f| %>
      <div class="field">  
        <%= attr_f.label "Field name" %>
        <%= attr_f.text_field :field_name %>
      </div>
      <div class="field">  
        <%= attr_f.label "Field value" %>
        <%= attr_f.text_field :field_value %>
      </div>
    <% end %>
  <% end %>

  <div class="actions">
    <%= f.submit %>
  </div>
...

And finally my characters_controller:

  def update
    respond_to do |format|
      if @character.update(character_params)
        format.html { redirect_to @character, notice: 'Character was successfully updated.' }
        format.json { render :show, status: :ok, location: @character }
      else
        format.html { render :edit }
        format.json { render json: @character.errors, status:  :unprocessable_entity }
      end
    end
  end

  private
    def set_character
      @character = Character.find(params[:id])
    end

    def character_params
      params.require(:character).permit(:id, :name, :player, :description, :character_type, attr4characters_attributes: [:id, :character_id, :field_name, :field_value])
    end

So, I have a form, which correctly display a character and all set of his attributes. When I update a character field (like :description), it is normally updated. When I update any nested field, Rails says that character is successfully updated and nothing changes! I searched with Google, and I found a lot of problems with nested attributes in Rails forms, but none of the recipes worked for me. I even encountered opinions that it is a bug in Rails 4, but I use 5th version...

Please, advice on the topic. Is it a bug really? Or am I doing something wrong? I'm new on Rails, so I don't exclude that possibility. :)

By the way, in the server's log I found that there is warning about attr4characters.

Processing by CharactersController#update as HTML
  Parameters: {"utf8"=>"\u2713", "authenticity_token"=>"xeYyIRc13YiOk29v18rFM6Oh5OHRRuPpSKEQuIHE/U4uhANEF7TwMp8mb6hv6L7mUAm5MngAuyFayHcWV/Vvbw==", "character"=>{"name"=>"Ray", "player"=>"111", "description"=>"A Zhong Lung suicider", "character_type"=>"Hsien", "attr4character"=>{"field_name"=>"Gift1", "field_value"=>"Sense Wyrm"}}, "commit"=>"Update Character", "id"=>"3"}
  Character Load (0.2ms)  SELECT  "characters".* FROM "characters" WHERE "characters"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
Unpermitted parameter: attr4character
   (0.1ms)  begin transaction
  SQL (0.9ms)  UPDATE "characters" SET "character_type" = ?, "updated_at" = ? WHERE "characters"."id" = ?  [["character_type", "Hsien"], ["updated_at", 2016-09-13 14:39:10 UTC], ["id", 3]]
   (24.3ms)  commit transaction

But attr4characters are permitted in the characters_controller...

Upvotes: 0

Views: 1128

Answers (1)

Frederick Cheung
Frederick Cheung

Reputation: 84114

The warning is telling you that it is ignoring all the attr4character attributes. Your permit code is correct as is your model, but your view doesn't match them. You should be doing

f.fields_for :attr4characters do |attr_f|
  ...
end

And let rails handle iterating over the association. This will also ensure that attributes are named correctly (so they will be allowed through by your whitelist)

Upvotes: 1

Related Questions