# How to deal with these 3 model's association?

**URL:** <https://www.ruby-forum.com/t/how-to-deal-with-these-3-models-association/151125>\
**Category:** Rails\
**Created:** [October 17, 2008, 5:35am UTC](https://www.ruby-forum.com/t/how-to-deal-with-these-3-models-association/151125 "2008-10-17T05:35:24Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![jette](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@jette](https://www.ruby-forum.com/u/jette)\
**Post date:** [October 17, 2008, 5:35am UTC](https://www.ruby-forum.com/t/how-to-deal-with-these-3-models-association/151125/1 "2008-10-17T05:35:24Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![jette](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@jette](https://www.ruby-forum.com/u/jette)\
**Post date:** [October 17, 2008, 6:56am UTC](https://www.ruby-forum.com/t/how-to-deal-with-these-3-models-association/151125/2 "2008-10-17T06:56:11Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![jette](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/d9b06d/32.png) [@jette](https://www.ruby-forum.com/u/jette)\
**Post date:** [October 17, 2008, 10:02am UTC](https://www.ruby-forum.com/t/how-to-deal-with-these-3-models-association/151125/3 "2008-10-17T10:02:22Z")

</div>

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.)  
Category  
\<%= select “item”, “category\_id”, @category.collect {|c| [ c.name,  
c.id ] }, { }, { :id =\> “category” } -%\>  
…  
Subcategory

  
\<%= render :partial =\> “subcat\_select”, :locals =\> {:s =\>  
@subcategories} -%\>  

  
…  
(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.
