# Help with many-to-many using :through

**URL:** <https://www.ruby-forum.com/t/help-with-many-to-many-using-through/56796>\
**Category:** Rails\
**Created:** [April 4, 2006, 5:57am UTC](https://www.ruby-forum.com/t/help-with-many-to-many-using-through/56796 "2006-04-04T05:57:27Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Vaishal\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/a3d4f5/32.png) [@Vaishal\_S](https://www.ruby-forum.com/u/Vaishal_S)\
**Post date:** [April 4, 2006, 5:57am UTC](https://www.ruby-forum.com/t/help-with-many-to-many-using-through/56796/1 "2006-04-04T05:57:27Z")

</div>

I am using many-to-many using :through since I need to store additional  
information in the join table.

I am doing this and it seems to work. I want to verify that this is the  
best  
way to do this.

Tables  
foods - id, food  
foodallergies - food\_id, symptom\_id, a few other columns  
symptoms - id, symptom

Models  
class Food \< ActiveRecord::Base  
has\_many :foodallergies  
has\_many :symptoms, :through =\> :foodallergies  
end

class Symptom \< ActiveRecord::Base  
has\_many :foodallergies  
has\_many :foods, :through =\> :foodallergies  
end

class Foodallergy \< ActiveRecord::Base  
belongs\_to :foods  
belongs\_to :symptoms  
end

I have a JournalEntry model that stores foods and symptoms as  
comma-seperated strings. Upon record creation in the JournalEntry, I  
want to  
parse the foods and symptoms and create a many to many relationship  
between  
them. I do this like this in the create method in the JournalController

def create  
params[:journal\_entry][“user\_id”] = @session[:user].id  
@journal\_entry = JournalEntry.new(params[:journal\_entry])

```
if @journal_entry.save
  # parse the foods and create a new record if food not already in 

```

db  
params[:journal\_entry][“eat”].split(%r{,\s\*}).each do |food|  
f = Food.find(:first, :conditions =\> [“food=?”, food.strip])  
unless f  
f = Food.create(:food =\> food)  
end

```
    params[:journal_entry]["symptoms"].split(%r{,\s*}).each do 

```

|symptom|  
s = Symptom.find(:first, :conditions =\> [“symptom=?”,  
symptom.strip])  
unless s  
s = Symptom.create(:symptom =\> symptom)  
end  
# create join  
f.foodallergies.create(:food\_id =\> f.id, :symptom\_id =\> s.id)  
end  
end

```
  flash[:notice] = 'JournalEntry was successfully created.'
  redirect_to :action => 'list'
else
  render :action => 'new'
end

```

end

Is this the best way to do it? Since I am using create, there is a  
database  
interaction on every ‘create’. Is there a way to leverage ActiveRecord  
functionality to batch the database interaction?

Thanks in advance,  
Vaishal

---

<div class="post-metadata">

**Author:** ![Vaishal\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/a3d4f5/32.png) [@Vaishal\_S](https://www.ruby-forum.com/u/Vaishal_S)\
**Post date:** [April 4, 2006, 6:20am UTC](https://www.ruby-forum.com/t/help-with-many-to-many-using-through/56796/2 "2006-04-04T06:20:45Z")

</div>

I can’t even get :through to work.

I get this error: ‘Unknown key(s): through’

Can anyone help?

Thanks!

---

<div class="post-metadata">

**Author:** ![Vaishal\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/a3d4f5/32.png) [@Vaishal\_S](https://www.ruby-forum.com/u/Vaishal_S)\
**Post date:** [April 4, 2006, 4:34pm UTC](https://www.ruby-forum.com/t/help-with-many-to-many-using-through/56796/3 "2006-04-04T16:34:11Z")

</div>

Thanks Josh. Nice example on your blog. May I suggest a tutorial on  
data  
entry using through with examples? A lot of people have posted examples  
about how to retrieve data using :through but I couldn’t find any on  
data  
entry issues.

Transactions…aha, I will try that out.

BTW, if instead of using create, I used the new method for foods,  
symptoms  
and foodallergies, would that work? Would rails then save everything in  
a  
batch? or would it not even allow me to do it because just using new  
will  
not get me an id for food or symptom and hence it wouldn’t know what to  
insert in the association?

Vaishal

---

<div class="post-metadata">

**Author:** ![Vaishal\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/a3d4f5/32.png) [@Vaishal\_S](https://www.ruby-forum.com/u/Vaishal_S)\
**Post date:** [April 4, 2006, 6:49am UTC](https://www.ruby-forum.com/t/help-with-many-to-many-using-through/56796/4 "2006-04-04T06:49:02Z")

</div>

Vaishal S. wrote:

> I am using many-to-many using :through since I need to store additional  
> information in the join table.
> 
> I am doing this and it seems to work. I want to verify that this is the  
> best  
> way to do this.

Your has\_many :through code looks solid to me. You might want to check  
the association examples on my blog if you run into trouble. I’ll be  
doing another one soon for working with attributes in a join model.

> Is this the best way to do it? Since I am using create, there is a database  
> interaction on every ‘create’. Is there a way to leverage ActiveRecord  
> functionality to batch the database interaction?

Wrap all the calls in a transaction. (JournalEntry.transaction do …  
end) When you commit the transaction all the new records will be saved  
en masse. You may also be able to get some leverage by using build()  
instead of create(), then when you call save on the parent object the  
children objects should be saved along with. I haven’t used the latter  
feature with :through associations yet, so I’m not sure how well that  
works. But the transaction thing should help a lot.

By the way, I suggest keeping the user\_id in the session, not the user  
object itself. It will save you a world of trouble trying to keep things  
in sync.

–  
Josh S.  
[http://blog.hasmanythrough.com](http://blog.hasmanythrough.com)

---

<div class="post-metadata">

**Author:** ![Vaishal\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/a3d4f5/32.png) [@Vaishal\_S](https://www.ruby-forum.com/u/Vaishal_S)\
**Post date:** [April 4, 2006, 4:34pm UTC](https://www.ruby-forum.com/t/help-with-many-to-many-using-through/56796/5 "2006-04-04T16:34:12Z")

</div>

are you are using Rails 1.1?
