# Has\_and\_belongs\_to\_many woes

**URL:** <https://www.ruby-forum.com/t/has-and-belongs-to-many-woes/85645>\
**Category:** Rails\
**Created:** [February 15, 2007, 5:26am UTC](https://www.ruby-forum.com/t/has-and-belongs-to-many-woes/85645 "2007-02-15T05:26:17Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mendake](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/d6d6ee/32.png) [@mendake](https://www.ruby-forum.com/u/mendake)\
**Post date:** [February 15, 2007, 5:26am UTC](https://www.ruby-forum.com/t/has-and-belongs-to-many-woes/85645/1 "2007-02-15T05:26:17Z")

</div>

I’m still having a hard time wrapping my brain around many to many  
relationships in rails. I understand what they are, and I’ve read all  
kinds of code that explains how to update them after finding a specific  
id. However, I can’t seem to figure out how to update a many to many  
model from a form. I just can’t imagine what the syntax might be.

Here are my models:

class Item \< ActiveRecord::Base  
has\_and\_belongs\_to\_many :print\_jobs  
end

class PrintJob \< ActiveRecord::Base  
has\_and\_belongs\_to\_many :items  
end

I have a table called “print\_jobs\_items” that contains the following  
fields:

print\_job\_id  
item\_id  
quantity  
dimensions

… I won’t list all the fields, but there are about 15.

I have an ajax form that points to the method “save\_item\_pj\_details”.  
The form object is called “items\_print\_job”. What do I actually put in  
that method to get rails to save the data from that form to the  
database, and add a new record if necessary. Do I have to manually  
create database objects for each table, or can I simply feed the form  
object to the model just as I normally would with the .new method?

I just (obviously) don’t have a clear picture of how to go about this,  
nor can I find any solid examples. Thanks very much.

---

<div class="post-metadata">

**Author:** ![mendake](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/d6d6ee/32.png) [@mendake](https://www.ruby-forum.com/u/mendake)\
**Post date:** [February 15, 2007, 3:15pm UTC](https://www.ruby-forum.com/t/has-and-belongs-to-many-woes/85645/2 "2007-02-15T15:15:22Z")

</div>

MenDAKE wrote:

> I’m still having a hard time wrapping my brain around many to many  
> relationships in rails. I understand what they are, and I’ve read all  
> kinds of code that explains how to update them after finding a specific  
> id. However, I can’t seem to figure out how to update a many to many  
> model from a form. I just can’t imagine what the syntax might be.
> 
> Here are my models:
> 
> class Item \< ActiveRecord::Base  
> has\_and\_belongs\_to\_many :print\_jobs  
> end
> 
> class PrintJob \< ActiveRecord::Base  
> has\_and\_belongs\_to\_many :items  
> end
> 
> I have a table called “print\_jobs\_items” that contains the following  
> fields:
> 
> print\_job\_id  
> item\_id  
> quantity  
> dimensions
> 
> … I won’t list all the fields, but there are about 15.

Ok, 2 things up front.

First, for the Rail magic to work, the table needs to be called  
‘items\_print\_jobs’. The tablenames must be in alpha order.

Second, this table probably shouldn’t have any other attributes (aside  
from item\_id and print\_job\_id) as they’re hard to get at and update when  
using has\_and\_belongs\_to\_many.

What you should probably consider instead is has\_many :through.

There’s some more detail on the pros, cons and debates at the  
many-to-many dance off on Josh S.s blog (  
[has\_many :through - Many-to-many Dance-off!](http://blog.hasmanythrough.com/2006/04/20/many-to-many-dance-off) ).

In your case, we replace that join table with a real live model.

I’m not sure what model is represented by the link between print\_job and  
item in your case, so I’ll just call it a Printing.

Item has\_many :printings  
Item has\_many :print\_jobs, :through =\> :printings

PrintJob has\_many :printings  
PrintJob has\_many :items, :through =\> printings

Printing has\_one :item  
Printing has\_one :print\_job

Thingy can then have as many attributes as it likes.

See Josh’s artuicle for more.

HTH

Alan

---

<div class="post-metadata">

**Author:** ![mendake](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/d6d6ee/32.png) [@mendake](https://www.ruby-forum.com/u/mendake)\
**Post date:** [February 15, 2007, 5:17pm UTC](https://www.ruby-forum.com/t/has-and-belongs-to-many-woes/85645/3 "2007-02-15T17:17:44Z")

</div>

Thanks, Alan. I now have my models set up with the :through method, and  
it seems to be working so far. My models now look like this:

class ItemsPrintJobs \< ActiveRecord::Base  
belongs\_to :print\_job  
belongs\_to :item  
end

class Item \< ActiveRecord::Base  
has\_many :items\_print\_jobs, :dependent =\> true  
has\_many :print\_jobs, :through =\> :items\_print\_jobs  
end

class PrintJob \< ActiveRecord::Base  
has\_many :items\_print\_jobs, :dependent =\> true  
has\_many :items, :through =\> :items\_print\_jobs  
end

The “ItemsPrintJobs” model references the table “items\_print\_jobs” and  
looks like this now:

id  
print\_job\_id  
item\_id  
quantity  
dimensions  
… again, I won’t list all the records.

This works fine for displaying information (just as the  
has\_and\_belongs\_to\_many relationship above did). However, I’m still not  
clear on the best procedure for updating these records with a form. I  
think this is just a basic AR/rails issue that I’m not clear on.

The problem is that when I go to save the items\_print\_jobs table I do  
not have the value of the id. I only have the value of the foreign keys  
“item\_id” and “print\_job\_id”. I need to be able to save a record if one  
already exists with those two foreign keys, or if not, create a new  
record.

The code I’m using below just creates record every time, presumably  
because it doesn’t know what the id (primary key) is.

# Use the form data object (items\_print\_job) to create a new db object.

@items\_print\_job = ItemsPrintJobs.new(@params[:items\_print\_job])

# Save the values of the two foreign keys.

@items\_print\_job.item\_id = @params[:item\_id]  
@items\_print\_job.print\_job\_id = @params[:id]

# Save the data to the database and add a flash message.

if @items\_print\_job.save  
flash[:notice] = “Product successfully saved”  
end

As an experienced programmer (though not in rails, obviously) I would do  
some if statements or perhaps create a composite primary key, but  
somehow I don’t think that’s how it’s supposed to work in rails. Can you  
help?

---

<div class="post-metadata">

**Author:** ![mendake](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/d6d6ee/32.png) [@mendake](https://www.ruby-forum.com/u/mendake)\
**Post date:** [February 15, 2007, 6:28pm UTC](https://www.ruby-forum.com/t/has-and-belongs-to-many-woes/85645/4 "2007-02-15T18:28:00Z")

</div>

Thanks for all your help. Looks like I finally have it working. Much  
appreciated.

---

<div class="post-metadata">

**Author:** ![mendake](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/d6d6ee/32.png) [@mendake](https://www.ruby-forum.com/u/mendake)\
**Post date:** [February 15, 2007, 5:39pm UTC](https://www.ruby-forum.com/t/has-and-belongs-to-many-woes/85645/5 "2007-02-15T17:39:45Z")

</div>

MenDAKE wrote:

> Thanks, Alan. I now have my models set up with the :through method, and  
> it seems to be working so far. My models now look like this:
> 
> class ItemsPrintJobs \< ActiveRecord::Base  
> belongs\_to :print\_job  
> belongs\_to :item  
> end
> 
> class Item \< ActiveRecord::Base  
> has\_many :items\_print\_jobs, :dependent =\> true  
> has\_many :print\_jobs, :through =\> :items\_print\_jobs  
> end
> 
> class PrintJob \< ActiveRecord::Base  
> has\_many :items\_print\_jobs, :dependent =\> true  
> has\_many :items, :through =\> :items\_print\_jobs  
> end
> 
> The “ItemsPrintJobs” model references the table “items\_print\_jobs” and  
> looks like this now:
> 
> id  
> print\_job\_id  
> item\_id  
> quantity  
> dimensions  
> … again, I won’t list all the records.
> 
> This works fine for displaying information (just as the  
> has\_and\_belongs\_to\_many relationship above did). However, I’m still not  
> clear on the best procedure for updating these records with a form. I  
> think this is just a basic AR/rails issue that I’m not clear on.
> 
> The problem is that when I go to save the items\_print\_jobs table I do  
> not have the value of the id. I only have the value of the foreign keys  
> “item\_id” and “print\_job\_id”. I need to be able to save a record if one  
> already exists with those two foreign keys, or if not, create a new  
> record.
> 
> The code I’m using below just creates record every time, presumably  
> because it doesn’t know what the id (primary key) is.
> 
> # Use the form data object (items\_print\_job) to create a new db object.
> 
> @items\_print\_job = ItemsPrintJobs.new(@params[:items\_print\_job])
> 
> # Save the values of the two foreign keys.
> 
> @items\_print\_job.item\_id = @params[:item\_id]  
> @items\_print\_job.print\_job\_id = @params[:id]
> 
> # Save the data to the database and add a flash message.
> 
> if @items\_print\_job.save  
> flash[:notice] = “Product successfully saved”  
> end
> 
> As an experienced programmer (though not in rails, obviously) I would do  
> some if statements or perhaps create a composite primary key, but  
> somehow I don’t think that’s how it’s supposed to work in rails. Can you  
> help?

How about:

@item = Item.find(params[:item\_id])  
@print\_job = @item.print\_jobs.find(params[:print\_job\_id])

That gets the items in question and searches its list of print\_jobs for  
a match.

If @print\_job is not null, the record exists and can be got via  
@item.printing or @print\_job.printing

If the @print\_job _is_ null, no relationship exists and you’ll need to  
create one.

Printing.create( params )

Does this make sense ?

Alternatively, you may be able to use  
Printing.find\_by\_item\_id\_and\_print\_job\_id( params[:item\_id],  
params[:print\_job\_id])

A.  
p.s. I’d definitely try and find a better name for that join model 🙂
