0

I'm struggling with this since a few days now and finally decided to ask even if I feel it should not be that hard to implement.

I'm using rails 3.1 and I want to be able to edit in a single form several records of the join table of a has_many :through association

I watched Ryan Bates' railscasts but this is not exactly what I'm looking for,

then I tried to implement this solution that looks very close to what I need, but it's not editing the join table.

This is the scenario: I have players (who are a sublass of User) who have many skills. Each player has a skill level that is stored in the player_skill model as an integer (1 to 10).

I am able to create and show players' skills and I can set values and store them in the DB, but I cannot retrieve existing values from the DB and show them as selected value in the dropdown menu. These are my models:

class Player < User

  has_many :player_skills, :dependent => :destroy
  has_many :skills, :through => :player_skills
  accepts_nested_attributes_for :skills

  attr_accessible :player_skills

end

class Skill < ActiveRecord::Base
  has_many :player_skills
  has_many :players, :through => :player_skills
end


# This stores the skill level as integer 1..10

class PlayerSkill < ActiveRecord::Base 
  belongs_to :player
  belongs_to :skill
end

I want to be able to edit all skills levels of a given player in a single form by means of a dropdown menu per each skill. For now I'm able to set and save them to the DB, but I cannot retrieve the values when I reload the edit form.

This is the code I use to create the edit form. I understand that my error is in the user of select, where I'm not loading the existing values, but I don't know how to do so.

<h3><%= @user.first_name %> <%= @user.last_name %></h3>
<% @skills = Skill.all %>
<%= form_for @user, :url => updateplayerskills_path(@user) do |f| %>


  <div class="field">
  <table border="1">
    <tr>
      <td>Skill Name</td>
      <td>Level</td>

    </tr>
    <% @skills.each do |skill| %>
      <%= f.fields_for :player_skills do |builder|  %>
        <tr>
      <td><%=h skill.name %></td>
      <td>

        #Here how can I load and display the existing level's value??
        #Shall I maybe use a different select method?

        <%= f.select skill.id, 1..10 %>     
      </td> 
      </tr>
      <% end %>
    <% end %>
  </table>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Any help / hint greatly appreciated! Thanks!

moncino07
  • 47
  • 1
  • 13

1 Answers1

2

I think you need to declare - accepts_nested_attributes_for for 'player_skills' rather than 'skills'.

So, class Player < User

        has_many :player_skills, :dependent => :destroy
        has_many :skills, :through => :player_skills
        accepts_nested_attributes_for :player_skills

Also, your current form snippet is like this:

<% @skills.each do |skill| %>
  <%= f.fields_for :player_skills do |builder|  %>
    <tr>
        <td><%=h skill.name %></td>
        <td>
            <%= f.select skill.id, 1..10 %>     
        </td> 
    </tr>
  <% end %>
<% end %>

I think it should be like this, instead:

<%= f.fields_for :player_skills do |builder|  %>
    <tr>
        <td>
            <%= builder.label :skill_id, "Skill" %>
            <%= builder.select(:skill_id, options_for_select(Hash[(1..10).collect { |n| [n.to_s, n] }])) %>     
        </td> 
    </tr>
<% end %>

EDIT:

If you want to generate the option list from a constant - 10, you can define the constant in the application_helper.rb

module ApplicationHelper
  MAX_SKILL_ID = 10
end

And then in your view:

<%= f.fields_for :player_skills do |builder|  %>
    <tr>
        <td>
            <%= builder.label :skill_id, "Skill" %>
            <%= builder.select(:skill_id, options_for_select(Hash[(1..ApplicationHelper::MAX_SKILL_ID).collect { |n| [n.to_s, n] }]), player_skill.level) %>     
        </td> 
    </tr>
<% end %>
Salil
  • 9,534
  • 9
  • 42
  • 56
  • Thanks Salil! I think we're _almost_ there. Actually your code shows up the dropdown menu with values from 1 to 6 ( I have 6 skills), but I need to show there the current value of player_skill.level and values from 1 to 10. The **ugly** solution I found so far is `<%= builder.select skill.id, options_for_select([['1',1],['2',2],['3',3],['4',4],['5',5],['6',6],['7',7],['8',8],['9',9], ['10', 10]], player_skill.level) %> ` – moncino07 May 15 '12 at 12:07
  • @moncino07, updated my answer according to the constant you need. Hope it helps. – Salil May 16 '12 at 01:58