Search code examples
ruby-on-railsruby-on-rails-3update-attributes

Given the index value how can I update only those values in a Rails controller?


I have a nested form as detailed below with a checkbox which I'm hoping to use to note only the records I want to update. I've checked the html and I'm registering the correct index for each record with it. The html for both an example attribute and the checkbox are as follows:

<input id="game_game_rosters_attributes_0_game_id" name="game[game_rosters_attributes][0][game_id]" type="hidden" value="127">
<input id="add_0" name="add[0]" type="checkbox" value="false">

Now, I think I'm supposed to figure out which game_roster_attributes I want to update by checking to see if the checkbox with the same index has a value of "true". But I'm unsure how to do this in my games_controller.rb, because it's currently set to mass assignment of my attr_accessible variables with @game.update_attributes()...

games_controller.rb

def update
  @game = Game.find(params[:id])

  respond_to do |format|
    if @game.update_attributes(params[:game])
       format.html { redirect_to @game, notice: 'Game was successfully updated.' }
       format.json { head :no_content }
    else
       format.html { render action: "edit"}
       format.json { render json: @game.errors, status: :unprocessable_entry }
    end
  end
end

Nested Form

<%= form_for @game do |f| %>

   # @game fields for editing here...

   <% roster_options.each.with_index do |option, index| %>
     <%= f.fields_for :game_rosters, option do |fields| %>
        <%= fields.object.player.full_name %>
        <%= fields.hidden_field :player_id %>
        <%= fields.hidden_field :game_id %>
        <%= check_box_tag 'add[' + index.to_s + ']', false %>
     <% end %>
   <% end %>

<% end %>

Models

game.rb

class Game < ActiveRecord::Base
  attr_accessible :date, :game_rosters_attributes
  has_many :game_rosters
  has_many :players, :through => :game_rosters
  accepts_nested_attributes_for :game_rosters, allow_destroy: true
end

game_roster.rb

class GameRoster < ActiveRecord::Base
  attr_accessible :active, :winner, :player_id, :game_id, :placement
  belongs_to :game
  belongs_to :player
end

game_controller.rb

def new
  @game = Game.new

  respond_to do |format|
    format.html # new.html.erb
    format.json { render json: @game }
  end
end

def edit
  @game = Game.find(params[:id])
  @game_roster = GameRoster.joins(:player).where(game_id: params[:id]).order('winner DESC, placement DESC')
  @options = SeasonRoster.where("season_id = (?) AND NOT EXISTS ( SELECT * FROM game_rosters INNER JOIN games ON games.id = game_rosters.game_id WHERE game_rosters.player_id = season_rosters.player_id AND games.id = (?))", @game.season_id.to_s, @game.id.to_s)

  @roster_options = Array.new
  @options.each do |o|
    c = GameRoster.new
    c.player_id = o.player_id
    c.challenge_id = params[:id]
    c.winner = false
    @roster_options.push(c)
  end

end

Solution

  • So after taking some time away from the problem and coming back to it I found a simple enough solution. I ended up just reversing the :_destroy checkbox that I had been using in the mean time.

    <%= fields.check_box :_destroy, {}, '0', '1' %>
    

    Basically, I just reversed the value of what the check box would usually represent. You can see where I edited the nested form to use this method below.

    Nested Form

    <%= form_for @game do |f| %>
    
       # @game fields for editing here...
    
       <% roster_options.each.with_index do |option, index| %>
         <%= f.fields_for :game_rosters, option do |fields| %>
            <%= fields.object.player.full_name %>
            <%= fields.hidden_field :player_id %>
            <%= fields.hidden_field :game_id %>
            <%= fields.check_box :_destroy, {}, '0', '1' %>
         <% end %>
       <% end %>
    
    <% end %>