Getting the associated model in a join table


#1

Let’s say we have the following models:

Product < ActiveRecord::Base
has_many :products_suppliers
has_many :suppliers, :through => :products_supplier

Supplier < ActiveRecord::Base
has_many :products_suppliers
has_many :products, :through => :products_supplier

ProductsSupplier < ActiveRecord::Base
belongs_to :supplier
belongs_to :product
end

Let’ say we have this data in the products_suppliers table:

| supplier_id | product_id |
| 1 | 2 |
| 1 | 1 |
| 2 | 2 |
| 2 | 1 |

So when I do this:

@suppliers = Product.find(1).suppliers, it will return an array with the
suppliers with id 1 and 2.

Let’s say I do this:

@supplier = @suppliers[0] #Which is the supplier with id = 1, the one
fetched from the (supplier_id = 1, product_id = 2) record in the
products_suppliers table. Ok, now I got a single instance of a supplier.
What I want is to get the product_id it was associated with in the
products_suppliers table.
(product_id = 2), might be missing something
simple, but I can’t seem to find a way to do that.

Any help appreciated!

Thanks,

Marcelo.


#2

Actually the question would be better put this way:

Having a has_one association via a link table (in this case
products_supplier).

Thanks.

On Mon, Apr 6, 2009 at 3:41 PM, Marcelo de Moraes S.
<removed_email_address@domain.invalid


#3

I couldn’t really get your question, but I think that what you are
trying to do here is to create a many to many relationship.

Rails actually provides the has_and_belongs_to_many association for
this very purpose, which should help you with what you are asking (I
think).

http://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many

On Apr 7, 6:01 am, Marcelo de Moraes S. removed_email_address@domain.invalid


#4

Hmm, maybe I’m complicating things. Maybe a delegate to the Product
class
(to get the product_id) would solve this… hmm, I will try that and let
you
guys know. Well, amazing how the fact of writing to the mailing list
helps
to find the solution by yourself :slight_smile:

Thanks!

Marcelo.

On Tue, Apr 7, 2009 at 12:28 PM, Marcelo de Moraes S. <


#5

Hello Jaryl, thanks for the reply,

habtm is equivalent to has_many :through. just that the join table is
not an
entity by itself, this I know :slight_smile:

So, I will try to explain through an example:

Let’s say we have a products table:

| id | name | price |
| 1 | a | 2.50 |
| 2 | b | 1.50 |

A suppliers table

| id | name |
| 1 | s_a |
| 2 | s_b |

So the idea is: A product may be supplied by many different suppliers.
So,
indeed, it is a has_and_belongs_to_many relationship. The thing is, the
relationship by itself defines the type of the supplier (if it’s either
a
vendor or a manufacturer), since we have:

products_suppliers table:
| id | supplier_id | product_id | supplier_type |
| 1 | 1 | 1 | “vendor” |
| 2 | 1 | 2 | “manufacturer”|

So, in tis case, supplier s_a is a “vendor” of product a and a
“manufacturer” of product b.

Product < ActiveRecord::Base
has_many :products_suppliers
has_many :suppliers, :through => :products_suppliers
end

Supplier < ActiveRecord::Base
has_many :products_suppliers
has_many :products, :through => :products_suppliers
end

ProductsSupplier < ActiveRecord::Base
belongs_to :product
belongs_to :supplier
end

So let’s take this code

p = Product.find(1)

What I need is a specific products_suppliers related to specific combo
of
(supplier_id,product_id) keys, so I can get the supplier_type data
related
to this product+supplier. However, I the has_many relationship in
Supplier
reaturns all the products_suppliers that has supplier_id == the id of
this
supplier – To get the specific products_supplier I would also need the
id
of the product that owns this supplier, but I can’t get it. So, the
first
thing I though was something like has_one :through. That’s why I said, a
has_one relationship through a link table. The thing is, I need the
product_id that owns this supplier from the supplier model. I might as
well
just leave AR and do some raw SQL, or maybe use sql :select statemente
in
the association to fetch the type from the link table into the
association.

Does that make sense?

Thanks,

Marcelo.


#6

I don’t think a delegate would work. Okay, just to recap on the
database structure:

products
| id | name | price |
| 1 | a | 2.50 |
| 2 | b | 1.50 |

suppliers
| id | name |
| 1 | s_a |
| 2 | s_b |

products_suppliers
| id | supplier_id | product_id | supplier_type |
| 1 | 1 | 1 | “vendor” |
| 2 | 1 | 2 | “manufacturer”|

Firstly, I don’t think that ‘products_suppliers’ is a good name since
this form is only a requirement for HABTM to work. It should be more
descriptive of the relationship, but your call.

Okay, so I believe that you want to do something like this:

p = Product.first

p.vendors # => [#< Supplier id: 1, name: “s_a”>, #<Supplier id: 2,
name: “s_b”>]
p.manufacturer # => #< Supplier id: 1, name: “s_a”>

You might want to try this:

class Product < ActiveRecord::Base
has_many :products_suppliers
has_many suppliers, :through => products_suppliers

named_scope :vendors, :conditions => [“supplier_type = ?”, “vendor”]
named_scope :manufacturer, :conditions => [“supplier_type = ?”,
“manufacturer”]
end

This does not restrict the manufacturer to a one-to-many relationship,
so you will have to ensure that each product will have only one
manufacturer (you can do this pretty easily with some validations).


#7

On Apr 7, 1:28 pm, Marcelo de Moraes S. removed_email_address@domain.invalid
wrote:

of the product that owns this supplier, but I can’t get it. So, the first
thing I though was something like has_one :through. That’s why I said, a
has_one relationship through a link table. The thing is, I need the
product_id that owns this supplier from the supplier model. I might as well
just leave AR and do some raw SQL, or maybe use sql :select statemente in
the association to fetch the type from the link table into the association.

Does that make sense?

Maybe this is too obvious, but given the example above, couldn’t you
just use:

p.products_suppliers.find_by_supplier_id(some_supplier_id)

That will give you the supplier that you’re looking for.

BTW, I’d recommend a different name for the supplier_type column -
that pattern (same as the foreign key, with _type instead of _id) is
the Rails convention for single table inheritance, which is NOT what
you’re looking for here. It shouldn’t cause a problem, but the AR
association code is known to sometimes get really weird indigestion
from that situation…

Hope this helps,

–Matt J.