Ok so I’m starting on normalising my database. Currently I have one model “Products” which is populated with about 60,000 products via a data feed (XML), which contains a product with a category name and a merchant name. I want to split these into 3 models; products, categories and merchants.
Each product has one category and one merchant so the natural idea is to create these models:
category_id | category_name
merchant_id | merchant_name
I can work out the code to associate between the models i.e. has_one, belongs_to etc but I’m struggling to work out to automatically associate a new Product with a category and a merchant programatically.
I’ve seen examples in books where your start with an empty database and that seems pretty straightforward. However, I’m starting off with a full database and a list of Category names.
Here is my product creation statement which is working great:
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 => node.xpath("./cat/text()").inner_text.downcase,
:price => "£" + node.xpath("./price/btext()").inner_text)
Would I need to do something like this, see the :category line, (i know the following is wrong btw!)…
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)
Any ideas? Does this even make sense!?
Assuming the columns are called
category_nameandmerchant_name, and you’ve set up the associations onCategoryandMerchant, you could do something like this:It will take a while, so for large datasets you might need a better solution.
.find_or_create_bydoes a find on the attribute and returns the matching row, or creates one if it does not exist. When creating the association via `.category=, Rails will set the foreign key to match the id of the row in the categories table.So to answer your question more directly:
is like doing this:
where the penultimate step sets the foreign key
category_idto the valuecategory.id. By convention associations are set up such that the foreign key is the model name suffixed with_id, so your products table should have bothcategory_idandmerchant_id.