Reputation: 3844
I don't even know where to start to explain my problem, so please bear with me :( !
I have two models; Product and Category - Product has_one Category and Category belongs_to Product
id
name
description
brand
merchant
price
image
link
category
id
name
product_id
Ok so now I'm looping through an XML feed create products like so:
Product.create(:name => node.xpath("./text/name/text()").inner_text.downcase,
:description => node.xpath("./text/desc/text()").inner_text,
:brand => node.xpath("./brand/text()").inner_text,
:merchant => node.xpath("../@name").inner_text,
:category => Category.find_by_name(node.xpath("./cat/text()").inner_text.downcase),
:price => "£" + node.xpath("./price/btext()").inner_text)
This appears to run great, until I look at what it's produced in the database... Here's the output from both tables.
id: 1
....
....
....
category: <---- empty for all 10,000+ records... err wtf? Surely should be a category ID or name
id: 1
name: socks
product_id: 10662 <---- err wtf?
id: 2
name: combinations
product_id: 10658 <---- err wtf?
id: 3
name: shoes
product_id: 9954 <---- err wtf?
id: 4
name: nightwear
product_id: 10653 <---- err wtf?
id: 5
name: hats
product_id: 10655 <---- err wtf?
id: 6
name: shorts
product_id: 10221 <---- err wtf?
id: 7
name: jeans
product_id: 9973 <---- err wtf?
id: 8
name: trainers
product_id: 8072 <---- err wtf?
To be honest I'm so confused, I'm not sure what I want to see anymore :-/
I just want the two tables to link together lol. Am I missing something fundamental here!?
Upvotes: 0
Views: 746
Reputation: 14621
When you use has_one / belongs to, only one of the models ends up containing the id of the other. In your case, since Category belongs_to Product
, the categories
table needs a product_id
column, where it'll store the ID of the product it belongs to.
But if Product has_one Category
(this also applies to has_many
), it doesn't need a category_id
column - Rails knows that to find the category (c) for a given product (p), it can just look through the categories
table for a category where product_id == p.id.
From the code you posted, it looks like Rails is doing what it should - even though the relationship is accessible from both models, only the model that has the belongs_to
directive has any relationship data stored in its table. In fact, Rails is smart enough to know that when you specify the {:category => cat} option when creating a Product, it should actually change the categories
table - and it does. That's why you're seeing product_id
s in your categories
table, and nothing in your products
table (and the column products.category
doesn't even need to exist - the relationship will work fine without it).
With that said, I suspect that a Product should be able to belong to more than one Category, and , likewise, a Category should be able to contain more than one Product. In that case, you'll want to use has_and_belongs_to_many in both models, and create the join table categories_products
to connect them...
Hope this clears things up!
Upvotes: 1
Reputation: 34340
There are a couple of changes you need to make. Firstly, your model structure should look like this:
class Product belongs_to :category end class Category has_many :products end
Secondly, your products table should have a category_id, not a category and your categories table should not have a product_id at all. Your code example should then run properly.
Upvotes: 1
Reputation: 1238
Your relationship is backwards. If you want a product to be in a single category you need:
Product
belongs_to :category
Category
has_many :products
Upvotes: 1