Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveSupport::HashWithIndifferentAccess on Embedded Form Update

I'm getting an ActiveSupport::HashWithIndifferentAccess error when I try to update an embedded form.

Here's the simplest example:

Form:

<h1>PlayersToTeams#edit</h1>
<%= form_for @players_to_teams do |field| %>
    <%= field.fields_for @players_to_teams.player do |f| %>
        <%= f.label :IsActive %>
        <%= f.text_field :IsActive %>
    <% end %>
    <%= field.label :BT %>
    <%= field.text_field :BT %>
    <br/>
    <%= field.submit "Save", class: 'btn btn-primary' %>
<% end %>

Models:

class PlayersToTeam < ActiveRecord::Base
  belongs_to :player
  belongs_to :team

  accepts_nested_attributes_for :player
end

class Player < ActiveRecord::Base
  has_many :players_to_teams
  has_many :teams, through: :players_to_teams
end

Controller:

class PlayersToTeamsController < ApplicationController
  def edit
    @players_to_teams=PlayersToTeam.find(params[:id])
  end

  def update
    @players_to_teams=PlayersToTeam.find(params[:id])
    respond_to do |format|
      if @players_to_teams.update_attributes(params[:players_to_team])
        format.html { redirect_to @players_to_teams, notice: 'Player_to_Team was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @players_to_teams.errors, status: :unprocessable_entity }
      end
    end
  end
end

This is the params[:players_to_team] object upon form submission:

:players_to_team

What does an ActiveSupport::HashWithIndifferentAccess error mean? What do I need to do to have this form update the players_to_team entry?

Edit

BT is a column in players_to_teams. If I remove teh field_for block, I can successfully save the BT field/the players_to_teams row.

Thanks

like image 838
Tyler DeWitt Avatar asked Apr 05 '12 01:04

Tyler DeWitt


1 Answers

Credit goes to @Brandan. Answered: What is the difference between using ":" and "@" in fields_for

Okay, I was able to clone your sample project and reproduce the error. I think I understand what's happening.

After your call to accepts_nested_attributes_for, you now have an instance method on your model named player_attributes=. This is in addition to the player= method that's normally defined for a has_one association. The player_attributes= method accepts a hash of attributes, whereas the player= method only accepts an actual Player object.

Here's an example of the text input generated when you called fields_for @players_to_teams.player:

<input name="players_to_team[player][name]" ... /> and here's that same input when calling fields_for :player:

<input name="players_to_team[player_attributes][name]" ... /> When you call update_attributes in your controller, the first example will call player=, while the second example will call player_attributes=. In both cases, the argument passed to the method is a hash (because params is ultimately just a hash of hashes).

That's why you were getting an AssociationTypeMismatch: you can't pass a hash to player=, only a Player object.

It appears that the only safe way to use fields_for with accepts_nested_attributes_for is by passing the name of the association and not the association itself.

So to answer your original question, the difference is that one works and the other doesn't :-)

like image 146
Tyler DeWitt Avatar answered Oct 21 '22 10:10

Tyler DeWitt