I have a table that currently belongs to 2 different models. What I'd like to do is turn these into a polymorphic association instead.
Currently the table line_items have a cart_id and an order_id now what I'd like to do is migrate both of these ids into a polymorphic one called itemable_id and fix the itemable_type to the correct one.
How would I go about creating a migration for this, or what's the go-to solution for this case, where you have two ids columns and want to make it polymorphic?
Try following and add belongs_to :itemable, polymorphic: true in LineItem model
rails generate migration RemoveCartRefFromLineItems cart:references
rails generate migration RemoveOrderRefFromLineItems order:references
rails g migration AddItemableIdToLineItems itemable_id:integer
rails g migration AddItemableTypeToLineItems itemable_type:string
Related
I have a table named product_categories. And I wanna create an self-relationship. What is the right way to do it using migrations generate command? I did this and it didnt work:
rails g migration AddProductCategoryToProductCategories productcategory:references
Just to summarize what worked in the comment section.
You must use
product_category
instead of
productcategory
Rails uses _ as a separator between names, called snake case. This can all be a little bit confusing when beginning to use Rails, and indeed even after using Rails for a long time. The guides are your friend...
http://edgeguides.rubyonrails.org/active_record_migrations.html
http://edgeguides.rubyonrails.org/association_basics.html
Generally speaking, the table name can be whatever you want it to be. I for one sometimes find Rails naming conventions a bit whacky.
If you've already generated the product_categories and products models/ tables, then just do:
rails generate model product_categories_products product_id:integer product_category_id:integer
This will generate a model that stores both foreign keys and acts as a proxy table.
You would then need to set up Product model with:
has_many product_categories_products
has_many product_categories, through: product_categories_products
Then define the following in ProductCategory
has_many product_categories_products
has_many products, through: product_categories_products
And Finally in ProductCategoryProduct
belongs_to product
belongs_to product_category
However, the above naming convention is horrible. You'd be better off renaming ProductCategory to just 'Category' and then your proxy table model can be 'ProductCategory'.
...or you could renaming it something completely different and then just manually specify the class_name in the association definitions.
I've got two tables in my Postgres database: categories and products.
I have a one to many relationship defined, one category can have many products.
After I've defined these in the two models in Rails, is there something else I need to do to the tables? I still have only the primary key that Rails defined when I set up each model separately.
You can run a migration generator with the right parameters to set up the foreign key.
bin/rails generate migration AddCategoryRefToProducts category:references
This assumes you have a Product model and Category model with these associations:
#product.rb
belongs_to :category
#category.rb
has_many :products
Run rake db:migrate to complete the process
When you look at your db/migrate directory you will see a file that contains an add_reference line within a def change block. Here's the reference for that method: Rails API. The syntax for the standalone generator is from the Rails Guides
In some previous stackoverflow questions, for example:
Rails 3 has_and_belongs_to_many migration
It suggests setting the :id => false for the join table of this association.
Now in the rails guides (for 4 presumably), it doesn't mention doing this in their example.
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
Is this still a requirement? I've done it with and it seems to work ok?
I believe in Rails 4 if you use the rails g migration CreateJoinTableCustomerProduct customer product it will create the join table with no primary key by default since this is the preferred style. You don't need a primary key in a join table like this.
I have a number of many-to-many relationships in my app.
I do not need to store information about the relationships themselves, so am using the has_and_belongs_to_many relation in my models.
I've read the Active Record documentation and it seems to confirm my strategy, BUT I'm not clear if I still need to create join tables in the database or if ActiveRecord in Rails 3.2 is smart enough to handle it using the model relations alone.
Any references or explanations would be appreciated.
----- Break -----
If I did need to store data about the relationship itself and I were using has_many => through in my model, would I need to remove the Primary Key from the "through" table (e.g. so that it only has the two foreign keys?)
Thank you!
Yes, you need to create the join table for a has_and_belongs_to_many association. Remember in Rails you need to 'migrate to create'. Using this article as an example, say we have an Account model and a Role model, we can create a join table through this migration:
rails generate migration create_accounts_roles_join_table
Now we will edit the migration file that was just created
create_table :accounts_roles, :id => false do |t|
t.integer :account_id
t.integer :role_id
end
It is important to include :id => false as this will leave off the primary key that is normally generated when you create a table. Also, we specified the two foreign keys account_id and role_id.
run rake db:migrate and add the HABTM associations in both models and everything is set up.
Also, as a side note, adding join_table to the end of the migration generator is not required but is more descriptive and integer can be replaced with references when adding the foreign keys. They are equivalent but maybe a bit more descriptive.
On the second part of your question, you don't need to remove the primary key from the table.
I execute the following commands to make the model:
script/generate model user firstname:string lastname:string
script/generate song group songname:string songtitle:string
a user has_many :songs and a song belongs_to :user
after this I run rake db:migrate however, the associations are not carried to my actual DB. Because in my actual DB I do not see any user_id column in songs table...etc.
Do we have to manually change the migration and add the needed columns?
To the best of my knowledge, you need to explicitly add the user_id to the migration file or when you are generating the model. I do now know of a way for it to detect the association and create the user key at least from the generate line:
I believe your options are:
script/generate song group songname:string songtitle:string user_id:integer
Or in the migration - adding this to your migration file:
t.integer :user_id
Or also adding this to your migration file. I don't believe you can do this from the command line. And you will need to do it after you create the belongs_to :user association in your songs.rb model.
t.references :user
As a note, I generally take the second option.
One other aside just on general ruby/rails convention - generally attribute names are lowercase and separated by underscores. so song_name instead of songname. That is entirely a taste thing and up to you as to how you want to implement.
I hope this helps!