views:

192

answers:

1

Read the big update for the latest information.

Hey everyone,

I've got a many-to-many relationship in a rails app that involves three tables: a user table, an interests table, and a join user_interests table that also has a rating value so a user can rate each of their interests on a 1-10 scale.

I am basically looking for a way for a new user to create their rating when they sign up and edit them at a future date along with any of their profile information at the same time.

I tried to follow this question http://stackoverflow.com/questions/2182428/rails-nested-form-with-has-many-through-how-to-edit-attributes-of-join-model but the problem I'm having is trying to incorporate a select list into the mix and having multiple interests to rate for the user.

Model Code:

user.rb
has_many :user_interests, :dependent => :destroy
has_many :interests, :through => :user_interests, :foreign_key => :user_id  
accepts_nested_attributes_for :user_interests

interest.rb
has_many :user_interests, :dependent => :destroy
has_many :users, :through => :user_interests, :foreign_key => :interest_id, :dependent => :destroy

user_interest.rb
belongs_to :user
belongs_to :interest

View Code:

app/views/user/_form.html.erb
<%= form_for(@user) do |form| %>
  ... user fields
  <%= form.fields_for :user_interests do |ui_form| %>
    ... loop through ALL interests
    <% Interest.all.each do |interest| %>
      <%= ui_form.select :rating, options_for_select(1..10) %>
      <%= ui_form.hidden_field :interest_id, :value => interest.id %>
    <% end %>
  <% end %>
<% end %>

I also included the following in the new/edit actions in my controller @user.interests.build.build_interest

The problem I'm running into is that only one interest rating is being passed in the params hash when I want to have multiple. Also I am getting an exception thrown by rails

Interest(#2172840620) expected, got Array(#2148226700)

What tiny detail did I miss or get wrong that is causing the problem?

EDIT:

I found a way to force this to work but it requires manually editing the HTML in chrome developer tools, the :name attribute of my form elements are being generated as user[user_interests_attributes][rating] but if I change it to user[user_interests_attributes][][rating] it will work when I update a record. However I can't manually specify the :name of a form element that is tied to a form object. So what can I do to show that multiple interest ratings are being passed instead of just one that rails thinks?

BIG Update:

Hey guys, I got a semi functional version going with some slight changes:

View code:

<% form.fields_for :user_interests do |ui_form| %>
<p>
    <%= ui_form.select :rating, options_for_select(1..5), :selected => :rating %>
    <%= ui_form.label :interest_title %>
    <%= ui_form.hidden_field :interest_id %>
</p>
<% end %>

Controller code:

def new
  @user = User.new
  Interest.all.each { |int| @user.user_interests.build({ :interest_id => int.id }) }
end

def edit
  @user = @current_user
  Interest.unrated_by_user_id(@user.id).each { |int| @user.user_interests.build({ :interest_id => int.id }) }
end

Now I am able to edit and get my user_interests updated or created if no rating exists, but I get an error that user is empty when I try to create a new user. Also I am unable to access any of the interest attributes in the form to display the interest the user is actually rating. Can anyone help with those caveats?

A: 

You only need @user.interests.build because its a has_many relationship. build_interest is for when there is a has_one/belongs_to relationship.

When using fields_for :user_interests you're telling the User model that an instance of one or more user_interest objects will be in the parameters hash when the user is created/updated. The form is not creating or updating any user_interests but it is sending back an array of user_interest_attributes hashes that represent the user_interests for the user the form references. This is an array of user_interests rating values for which no user_interests exist as you reference them in the form which is the reason you get the error.

Since you are passing a range to the select form helper you aren't actually providing any interests to the form for selection. The select will set a value for the rating column in the user_interests table with a value between 1 and 10. No user_interest exists for the rating to be set on even if the user_interests table has a rating column.

passing :multiple => true in the options hash of the select tag will create a multiple select list but I don't think that is what you want. I think you want many items on a page the user can put an interest rating on.

If you do want a user to be able to select many interests this is how to use fields_for with accepts_nested_attributes_for on a has_many :through relationship:

<%= form_for(@user) do |f| %>
  <% f.fields_for :interest_ids  do |interest| %>
    <ul>
      <% Interest.all.each do |choice,i| %>
      <li class="selection">
        <%= interest.check_box [], { :checked => f.object.user_interest_ids.include?(choice.id) }, choice.id, ''  %>
        <%= interest.label [], choice.name %>
      </li>
    <% end %>
    </ul>
  <% end %>
<% end %>
inkdeep
I am working on this now, looks like I left out my loop of all of the interests in my view out of my code samples above, I will modify it to reflect what I had originally to maybe shed some more light
Jimmy
Yeah I'm not trying to have check marks for each interest but a dropdown with a rating value for each interest
Jimmy