Question

I'm using Rails 4, and with it Strong Params. For some reason I can't save my nested parameters. I've looked at how to do it and even might've gotten it working in a different Rails app before. I know to permit draft_players_attributes and list all of it's accepted params in an array.

Here are the params coming in:

Started POST "/draft_groups" for 127.0.0.1 at 2013-12-04 22:55:32 -0500
  User Load (1.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Processing by DraftGroupsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"2W3bs1U7+CEzsWl+jDi3xZi5CyldYeZXCz3KU6c+sYY=", "draft_group"=>{"name"=>"Best Group Ever", "draft_id"=>"3", "captain_id"=>"1"}, "draft_players"=>{"player_id"=>"1", "position"=>"Handler", "rating"=>"10", "info"=>"Smart"}, "commit"=>"Update"}
   (0.3ms)  BEGIN
  SQL (2.6ms)  INSERT INTO "draft_groups" ("captain_id", "created_at", "draft_id", "name", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["captain_id", 1], ["created_at", Thu, 05 Dec 2013 03:55:32 UTC +00:00], ["draft_id", 3], ["name", "Best Group Ever"], ["updated_at", Thu, 05 Dec 2013 03:55:32 UTC +00:00]]
   (0.5ms)  COMMIT
Redirected to http://lvh.me:3000/drafts/3
Completed 302 Found in 8ms (ActiveRecord: 3.3ms)

Here's my controller:

class DraftGroupsController < ApplicationController
  def create
    @draft_group = DraftGroup.create(draft_group_params)
    redirect_to :back, :notice => "Draft Group successfully created."
  end

  def update
    @draft_group = DraftGroup.find(params[:id])
    @draft_group.update(draft_group_params)
    redirect_to :back, :notice => "Draft Group successfully updated."
  end

  def destroy
    @draft_group = DraftGroup.find(params[:id]).destroy
    redirect_to :back, :notice => "Draft Group successfully destroyed."
  end

  private
  def draft_group_params
    params.require(:draft_group).permit(:name,
                                        :draft_id,
                                        :captain_id,
                                        draft_players_attributes:
                                          [
                                            :_destroy,
                                            :id,
                                            :player_id,
                                            :position,
                                            :rating,
                                            :info
                                          ]
                                       )
  end
end

And my models:

class DraftGroup < ActiveRecord::Base
  has_many :draft_players, :dependent => :destroy
  belongs_to :captain, :class_name => "User"

  accepts_nested_attributes_for :draft_players
end

class DraftPlayer < ActiveRecord::Base
  belongs_to :draft_group
  belongs_to :player, class_name: "User"
end

And my view:

<% @groups.each do |group| %>
  <div class="span6 group">
    <h4><%= "#{group.name}" %></h4>
    <%= simple_form_for(group, :html => { :class => "auto-width" } ) do |f| %>
      <div class="row">
        <%= f.input :name, :label => false %>
        <%= f.hidden_field :draft_id %>
        <%= f.hidden_field :captain_id %>
      </div>
      <table>
        <tr>
          <th>Player</th>
          <th>Position</th>
          <th>Rating</th>
          <th>Info</th>
        </tr>
        <%= simple_fields_for :draft_players do |player| %>
          <tr>
            <td><%= player.input :player_id, :label => false, :as => :select, :collection => User.active %></td>
            <td><%= player.input :position, :label => false %></td>
            <td><%= player.input :rating, :label => false %></td>
            <td><%= player.input :info, :label => false %></td>
          </tr>
        <% end %>
      </table>
      <div class="row">
        <%= f.button :submit, "Update", :class => "btn btn-primary" %>
      </div>
    <% end %>
  </div>
<% end %>

EDIT: Added view code, and will probably take table out, shifting it into using bootstraps columns layout.

Was it helpful?

Solution

To make sure parameters are nested correctly (and so Rails can understand nested model attributes) you should call f.simple_fields_for(:draft_players) rather than simple_fields_for(:draft_players).

In other words, call simple_fields_for on the FormBuilder object f rather than calling the helper directly.

That way Rails can look up and validate the nested association correctly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top