# Converting from HABTM to has\_many :through

**URL:** <https://www.ruby-forum.com/t/converting-from-habtm-to-has-many-through/117323>\
**Category:** Rails\
**Created:** [October 15, 2007, 11:55pm UTC](https://www.ruby-forum.com/t/converting-from-habtm-to-has-many-through/117323 "2007-10-15T23:55:59Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![avramd](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/aca169/32.png) [@avramd](https://www.ruby-forum.com/u/avramd)\
**Post date:** [October 15, 2007, 11:55pm UTC](https://www.ruby-forum.com/t/converting-from-habtm-to-has-many-through/117323/1 "2007-10-15T23:55:59Z")

</div>

Hello,

I have a has\_and\_belongs\_to\_many relationship that I’ve realized I need  
to add additional attributes to. So I’m converting it to a has\_many  
:through (HMT) relationship. This is the first time I’ve used an HMT,  
and it seems like I’m using too much code. I couldn’t figure out how to  
get the join model objects to update automatically as a result of  
updating the primary object, so I’ve ended up doing individual  
saves/updates on each join model object.

The story is a regatta can include many boat classes, and a boat class  
can be included in many regattas.

class Regatta \< ActiveRecord::Base  
has\_many :inclusions  
has\_many :boat\_classes, :through =\> :inclusions  
has\_and\_belongs\_to\_many :users  
end

class BoatClass \< ActiveRecord::Base  
has\_many :inclusions  
has\_many :regattas, :through =\> :inclusions  
end

class Inclusion \< ActiveRecord::Base  
belongs\_to :regatta  
belongs\_to :boat\_class  
end

Eventually, I’ll attach a fee to each boat\_class when it gets included  
in a regatta. But for now I’m just trying to get back to the same  
functionality I had when it was a HABTM relationship, and there was no  
“include” model. So, here is what the update method looks like now:

```
@regatta = Regatta.find(params[:id])
Inclusion.find_all_by_regatta_id(params[:id]).each { |i|
    boat_class = i.boat_class
    if params[:boat_classes]
        i.included = params[:boat_classes].include? boat_class.id
        params[:boat_classes].delete boat_class.id
    else
        i.included = false
    end
    flash[:notice] = 'inclusion failure' if !

```

i.update\_attribute(:included, i.included)  
}  
params[:boat\_classes].each { |boat\_class\_id|  
boat\_class = BoatClass.find boat\_class\_id  
logger.info “\*\*\* boat class #{boat\_class.name} inclusion not  
found”  
@regatta.inclusions \<\< Inclusion.new { |i|  
i.boat\_class\_id = boat\_class\_id  
i.included = true  
flash[:notice] = ‘inclusion failure’ if ! i.save  
}  
} if params[:boat\_classes]  
@regatta.users = User.find(params[:users]) if params[:users]  
if @regatta.update\_attributes(params[:regatta])  
flash[:notice] = ‘Regatta was successfully updated.’  
redirect\_to :action =\> ‘show’, :id =\> @regatta  
else  
render :action =\> ‘edit’  
end

It seems to me that I shouldn’t have to individually update all the  
existing inclusions, or manually create & save the new ones. I’d like  
suggestions for how I can reduce the amount of code here. Considering  
that the first 20 lines used to simply be:

```
@regatta = Regatta.find(params[:id])
@regatta.boat_classes = User.find(params[:boat_classes]) if

```

params[:boat\_classes]

Additional background info: a) this keeps the join model objects around  
even when a boat\_class gets excluded, so that it’s attributes will be  
saved. That’s not critical, if I can have it be much tighter, I’m happy  
to give that up. b) there is a bug in this that I haven’t found yet, but  
is irrelevant to this question: this code creates a new inclusion even  
when there is an existing one found already. It seems params[…].delete  
is not working the way I expect it to.

Thanks for any help,  
Avram
