How to deal with these 3 model's association?

Now I have 3 models, item category and sub-category and 3 Tables in my database.

I planed to set the association like this.

Item Belongs_to :category Belongs_to :sub-category

category Has_many :items Has_many :sub_category

sub_category belongs_to :category Has_many :items

And now I want to have some dynamic drop down list in the items/new page When I chose one category, and the sub-category will dynamically updated. what other move do I need?

Is that right? It makes me feel confused with these associations.

Jette Chan wrote:

Now I have 3 models, item category and sub-category and 3 Tables in my database.

I planed to set the association like this.

Item Belongs_to :category Belongs_to :sub-category

category Has_many :items Has_many :sub_category

sub_category belongs_to :category Has_many :items

And now I want to have some dynamic drop down list in the items/new page When I chose one category, and the sub-category will dynamically updated. what other move do I need?

Is that right? It makes me feel confused with these associations.

category.rb has_many :sub_categories has_many :items ,:through=>:sub_categories

sub_category.rb belongs_to :category has_many :items

item.rb belongs_to :sub_category

by use of this association you can define get any of 2 by select of any of 1 among three models

for that use Ajax Updater

A subcategory is always a child of a category. Lets set up your associations as such. It will use only one db column instead of two. Each item will belong to a subcategory; each subcategory will belong to a category. It will look something like this:

Category     / \ Subcategories    / | \ Items Items Items

We will use ActiveRecord's :through association. Your models will look like this:

Class Category    has_many :subcategories    has_many :items, :through => :subcategory

Class Subcategory    has_many :items

Class Item    belongs_to :subcategory

When you do this, Category will associate with an Item by tunneling through Subcategory. These helpful methods will now be available:

Item.category Item.subcategory Subcategory.category

Category.items Category.subcategories Subcategory.items

Now, we need to do your drop down list (called a "select" in Rails) magic. I'm not much of a Javascript buff, so this is a dirty little hack that *should* work. The idea is to have the "subcategory" select contained in a DIV. The contents on the DIV will originate from an action that only deals with creating that select, likewise it will render a partial containing only the select's markup. We'll have an observer watch the "category" select, and send whatever it changes to to the "subcategory" select handler, which will in turn re-render the select with the appropriate contents. Your controller, model, view, and partial should look like this:

Item Controller:   def subcategory_handler     @subcategories = Category.find(params[:category_id]).subcategories     render :partial => "subcat_select", :locals => {:s => @subcategories}   end ### put this in the method "new":     @category = Category.find :all     @subcategories = @category[0].subcategories

Item model: ### add this virtual attribute, so that we don't get NoMethod errors:     attr_accessor :category_id

Partial _subcat_select.html.erb     <%= select "item", "subcategory_id", s.collect {|s| [ s.name, s.id ] } -%>

View for Item#new: (I assume that the values in your select options are the category and subcategory IDs.)    <label>Category</label>       <%= select "item", "category_id", @category.collect {|c| [ c.name, c.id ] }, { }, { :id => "category" } -%> ...    <label>Subcategory</label>       <div id="subcategory_container">          <%= render :partial => "subcat_select", :locals => {:s => @subcategories} -%>       </div> ... (This must be called AFTER your select fields are defined!)    <%= observe_field :category, :url => { :action => :subcategory_handler }, :with => :category_id, :update => "subcategory_container" %>

That's a pretty rough hack, but I tested it on Rails 2.1.0 and it works. It'll take some fine tuning on your part. There might be a completely different way of handling such a thing, this is only one option to explore.

Hope it makes sense.