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
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 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
I am new to ruby on rails. I have created a many-to-many association and a migration, such as follows:
in Foo model:
has_and_belongs_to_many bars
in Bar model:
has_and_belongs_to_many foos
and the migration for join table has the following content:
def change
create_table :foos_bars, id: false do |t|
t.references :foo
t.references :bar
end
end
Now I see that the association should be one-to-many as: foo has many bars.
I don't know if I have generated controllers after the above migration, but I know that the file of the above migration is the last one that was created in the migrate folder. Also I have not made any connection yet between any foo and any bar.
Can I do the following to start fresh (change the association and also remove the file of the migration):
use 'rake db:rollback'
delete the file of the join table migration (i.e. timestamp_create_bars_foos.rb file)
change the 'has_and_belongs_to_many' in foo to 'has_many', and in bar to 'belongs_to'
run: 'rails generate migration CreateFoosBars'
run: 'rake db:migrate'
If not, what can I do to make the above modification for the association?
Thanks in Advance!
The steps you have listed looks good.
The only thing that stands out is the intention to CreateFoosBars again in Step 4 : rails generate migration CreateFoosBars'.
Since the foos and bars tables are already created, and this is a has_many relationship, you just need to add a reference for foo in the bars table, and not create a new table.
Something along the lines of:
rails g migration add_foo_id_to_bar foo_id:integer
Would advise reviewing Rails 3 migrations: Adding reference column? to figure out what the migration should do.
I am new to rails (usually a python guy) and have just been trying to build a simple task manager application for fun. I am using Devise for authentication and have a single Task object I am trying to relate to a user. I have added the following to the Task model:
class Task < ActiveRecord::Base
belongs_to :user
end
and I have added the following in my User model for Devise:
class User < ActiveRecord::Base
has_many :tasks
<<normal Devise stuff>>
end
Whenever I added this information I then ran: rake db:migrate. It then gave me an error that the database field did not exist for user_id when I tried to do anything with it.
I am sure it is something rather simple that I am missing. Thanks for the help.
Adding a belongs_to (or any other) relationship to your model only tells active record that models are linked logically. This gives you access to methods like task.user. For this to actually work, the instances must be linked via database fields.
This is the step you're missing: you need to create a migration that will add a column to the Task table indicating which user it belongs to.
rails g migration AddUserIdToTasks user_id:integer
Note AddUserIdToTasks can be whatever name you want. It makes no difference. You can then open db/migrations/add_user_to_tasks and see what it does. Usually self.up will modify the database how you want it and self.down will do the opposite (so, in this case, remove the used_id).
Then to actually execute the SQL commands to alter the database table and schema, run
rake db:migrate
You need to generate a migration to add the foreign key first:
rails g migration AddUserIdToTasks user_id:integer
Then run db:migrate
And if you want the user to be able to reference the association as user.dreams, you need to add :class_name => 'Task' to the has_many line in the User model.
Your user class seems to be too dreamy to take care of it's tasks.
has_many :dreams // should be probably
has_many :tasks
Assuming that you tasks model has a user_id field, that is.
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!