Topic: checkbox and :through

I have a two tables joined with has_many :through.

Model:

class Part < ActiveRecord::Base
  has_many :features, :through => :feature_parts
end
class FeaturePart < ActiveRecord::Base
  belongs_to  :part
  belongs_to  :feature
end
class Feature < ActiveRecord::Base
  has_many :parts, :through => :feature_parts
end

The feature table has 20 rows in it with :name and :category as the columns.

When I am on the edit.rhtml for a Part, I want to have checkboxes, and beside each checkbox would be the :name of the feature, one for each row in feature.  The initial state of the checkbox should be set based on if there is a pertinent row in FeaturePart.

What's the clean/right way to do this?

Thanks,

Damon

Re: checkbox and :through

It would go something like this i guess:

<h2>Features for this part:</h2>
<ul>
<% Feature.find(:all, :order => "name ASC").each do |p|  %>
   <li><%= check_box_tag 'part[feature_ids][]', p.id, @part.features.include?(p) %>
<%= p.name %></li>
<% end %>
</ul>

These boxes should only be checked if the feature is already associated with said part.

vinnie - rails forum admin

Re: checkbox and :through

Can you do @part.features when you have a :through relationship?  I thought that was only available as a regular has_many...

I've seen lots of blogs/wikis for how to setup the :through relationship, but not too much about how to query from that relationship.

Thanks,

Damon

Re: checkbox and :through

You sure can.  has_many :though works in almost the same way as habtm, except it gives you better access to the join table/model.

Re: checkbox and :through

So this is what I have:

Database

ActiveRecord::Schema.define(:version => 3) do

  create_table "feature_parts", :id => false, :force => true do |t|
    t.column "feature_id", :integer
    t.column "part_id", :integer
  end

  create_table "features", :force => true do |t|
    t.column "name", :string
    t.column "category", :string
  end

  create_table "parts", :force => true do |t|
    t.column "model", :string
    t.column "brand", :string
  end

end


Model
class Part < ActiveRecord::Base
  has_many :features, :through => :feature_parts
end
class Feature < ActiveRecord::Base
  has_many :features, :through => :feature_parts
end
class FeaturePart < ActiveRecord::Base
  belongs_to  :part
  belongs_to  :feature
end

Controller
  def edit
    @part = Part.find(params[:id])
  end

View (Other stuff removed)
 <ul>
<% Feature.find(:all, :order => "name ASC").each do |p|  %>
    <li><%= check_box_tag 'part[feature_ids][]', p.id, @part.features.include?(p) %>
<%= p.name %></li>
<% end %>
</ul>

And it produces the error (I must have defined my models wrong?):


ActiveRecord::HasManyThroughAssociationNotFoundError in Admin#edit

Showing app/views/admin/_form.rhtml where line #12 raised:

Could not find the association :feature_parts in model Feature

Extracted source (around line #12):

9:
10:  <ul>
11:  <% Feature.find(:all, :order => "name ASC").each do |p|  %>
12:     <li><%= check_box_tag 'part[feature_ids][]', p.id, @part.features.include?(p) %>
13:  <%= p.name %></li>
14:  <% end %>
15:  </ul>

Last edited by damonbrodie (2006-06-27 11:11:40)

Re: checkbox and :through

what does your db look like?

Re: checkbox and :through

damonbrodie wrote:

class Feature < ActiveRecord::Base
  has_many :features, :through => :feature_parts
end

Shouldn't this be...

class Feature < ActiveRecord::Base
  has_many :parts, :through => :feature_parts
end

Railscasts - Free Ruby on Rails Screencasts

Re: checkbox and :through

Yes it should (copy and paste error in my test project).  I still get the same error message though.

Re: checkbox and :through

Here is a copy of the database schema if that helps:

ActiveRecord::Schema.define(:version => 3) do

  create_table "feature_parts", :id => false, :force => true do |t|
    t.column "feature_id", :integer
    t.column "part_id", :integer
  end

  create_table "features", :force => true do |t|
    t.column "name", :string
    t.column "category", :string
  end

  create_table "parts", :force => true do |t|
    t.column "model", :string
    t.column "brand", :string
  end

end

Re: checkbox and :through

Oh yeah, in order to use :through, you have to define the through association.

class Part < ActiveRecord::Base
   has_many :feature_parts, :dependent => true
   has_many :features, :through => :feature_parts
end

However, this is only if you need access to feature_parts.  You should just be able to use habtm.

 class Part < ActiveRecord::Base
   has_and_belongs_to_many :features, :join_table  => 'feature_parts'
end

class Feature < ActiveRecord::Base
   has_and_belongs_to_many :parts, :join_table  => 'feature_parts'
end


You could also avoid having to declare the join_table attribute by changing feature_parts to features_parts.

Re: checkbox and :through

First of all, thanks for everyone that has helped on this so far.  I've made lots of progress understanding rails with your help.

I'm working on a search page that has checkboxes on it for all the features.  The goal would be that the search would return a list of parts that have all of the selected features (i.e. they are ANDed together).

Is the right way to programatically build the :conditions of the find?  How would that be done?

Any pointers?