How can I set up relations for these models?


#1

Hello!

I have a legacy DB and want to use ActiveRecord for it.
However, I can’t set up a relation correctly.

Here’s table spec:

[products]
id
name
price

[subproducts]
product_id
subproduct_id

Some example data:

[products]
1, “Computer”, 500.00
2, “Monitor”, 200.00
3, “Printer”, 100.00
4, “System”, 700.00
5, “System2”, 650.00

“System” is made up of “Computer”, “Monitor”, and “Printer”
“System2” is made up of “Computer” and “Printer”

So [subproducts] table will have the following rows.

4, 1
4, 2
4, 3
5, 1
5, 2

“Computer” can be sold by itself or as a part of “System”.

class Product < ActiveRecord::Base
#???
end

How do I set up relations?
It seems like a many-to-many relation.
But I’m stuck here.

Thansk.
Sam


#2

First thing I would do is try this:

class Product < ActiveRecord::Base
has_many :subproducts
end

class Subproduct < ActiveRecord::Base
belongs_to :product
set_primary_key “subproduct_id”
end

Now I don’t know what subproducts are but I assume that ‘product_id’
is the parent id and subproduct_id is the primary key of the table but
a foreign key to the actual product itself.

That gets tricky but not really impossible.

p = Product.find(1)
new_product = Product.create :name=>“Computer”, :price=>500
p.subproducts << SubProduct.create :subproduct_id =>new_product.id

And you could pretty that up by making your own add_subproduct method
on your model. A rushed and untested example might be this:

class Product < ActiveRecord::Base
has_many :subproducts

def add_subproduct(product_id)
self.subproducts << Subproduct.create :subproduct_id => product_id
end

def remove_subproduct(product_id)
self.subproducts.remove(product_id)
end
end

p = Product.find(1)
s = Product.find(2)
p.add_subproduct s.id
p.remove_subproduct s.id

Would that work?


#3

Hi, Brian,
Thank you for the answer.

I need to make one thing clear.

subproducts table is just a join table which doesn’t have a primary
key(id).
See the example data for subproducts.

product_id, subproduct_id
4, 1
4, 2
4, 3
5, 1
5, 2

subproduct_id can’t be a primary_key just by itself.
Primary key would be the composite of product_id and subproduct_id.

This is a many-to-many relation.
But the difference is that this relation is between one table instead of
two.

Usually a many-to-many is like between student-to-class.
But my case is like product-to-product.

What do you think?

Sam


#4

Oh, I think that it’s exactly what I want.
Thanks!

Sam


#5

Do you mean to say that it is possible for a subproduct to belong to
more than one product? Cos that’s what this implies.

That’s easy though… you should look here:

http://rails.techno-weenie.net/tip/2006/4/12/self_referential_many_to_many_relationships

That will do it for you then!


#6

Sam K. wrote:

Oh, I think that it’s exactly what I want.
Thanks!

That should work fine if all you need is a join table. If you want to
keep additional attributes in the subproducts table (like maybe number
of units?), you’ll want to use a self-referential join model.

http://blog.hasmanythrough.com/articles/2006/04/21/self-referential-through


Josh S.
http://blog.hasmanythrough.com


#7

Josh S. wrote:

Sam K. wrote:

Oh, I think that it’s exactly what I want.
Thanks!

That should work fine if all you need is a join table. If you want to
keep additional attributes in the subproducts table (like maybe number
of units?), you’ll want to use a self-referential join model.

http://blog.hasmanythrough.com/articles/2006/04/21/self-referential-through

Wow, how did you know that?
I need additional attributes in the subproducts table.
I was thinking about it and you already answered.

Thank you so much.
Sam


#8

Sam K. wrote:

Wow, how did you know that?
I need additional attributes in the subproducts table.
I was thinking about it and you already answered.

I’ve been answering questions on this list for a while. I guess I’m
learning what usually comes next :slight_smile:

cheers!


Josh S.
http://blog.hasmanythrough.com