I have User with primary key id and a Blog model with primary key id.
I have a has_many association in User to the Blog and a belongs_to in Blog
to User.
From what I understand I need to manually to the modifications to the schema.
Could you provide an insight on how to do this ?
# app/models/user.rb
class User < ActiveRecord::Base
has_many :blogs
end
# app/models/blog.rb
class Blog < ActiveRecord::Base
belongs_to :user
end
# db/migrate/20131103182551_add_user_id_to_blogs.rb
class AddUserIdToBlogs < ActiveRecord::Migration
def change
add_column :blogs, :user_id, :integer
end
end
Then run rake db:migrate. You can then call user.blogs or blog.user.
You have to do what you have already said above and then ALSO change the database schema. You change the database schema through migrations. The step that you are missing is => You need to add the foreign key of user_id to blogs (You do this through a migration) or add a belongs to relationship
You can create the migration with a 'rails generate migration' command
rails generate migration add_column :blogs, :user_id, :integer
OR
rails generate migration change_table :blogs, :belongs_to, :user
The result of the migration should add the foreign key of user_id to blogs or it should add the belongs_to association between user and blogs.
Look for the result of your migration in the db/migrate folder
Then run
rake db:migrate
Related
I have two models: User and Post.
In order to make an association between them I type this into the console:
rails generate migration add_user_id_to_posts user_id:references
This creates migration:
def change
add_reference :posts, :user_id, foreign_key: true
end
However, when I look into the database, it shows that I created 'user_id_id' column and not 'user_id' which I expected. What mistake am I making?
If you specify references option just provide model name
rails generate migration add_user_to_posts user:references
def change
add_reference :posts, :user, foreign_key: true
end
I need to need to make a column as foreign key.
I did lot of research on it.
I understood that I need to add associations. I am clear on belongs_to , has_one and has_many options.
After creating associations rails know that there is a foreign key association.If I remove the main record then dependent record will be deleted by rails app.
I was reading on migrations and I came across http://edgeguides.rubyonrails.org/active_record_migrations.html
where it is mentioned:
$ bin/rails generate migration AddUserRefToProducts user:references
will generate:
class AddUserRefToProducts < ActiveRecord::Migration
def change
add_reference :products, :user, index: true, foreign_key: true
end
end
Now on website: http://guides.rubyonrails.org/active_record_migrations.html
where it is mentioned:
$ bin/rails generate migration AddUserRefToProducts user:references
will generate:
class AddUserRefToProducts < ActiveRecord::Migration
def change
add_reference :products, :user, index: true
end
end
I understand the creation of index.
Do I need to have foreign_key: true explicitly or not? what difference will it make?
If you specify the foreign key in your migration, Rails will add a foreign key constraint at the database level. If you leave it out, no constraint will be added and it will behave like all previous versions of Rails e.g. you can delete records with the risk of orphaned records being left behind.
You can do something like
class AddUserRefToProducts < ActiveRecord::Migration
def change
add_reference :products, :user, index: true
add_foreign_key :products, :user
end
end
Similar solution here
First of all according to my knowledge http://edgeguides.rubyonrails.org/active_record_migrations.html is yet to be released. so the change foreign_key: true in your migration is not applicable yet so it wont make difference.
See this http://edgeguides.rubyonrails.org/index.html.
For stable versions, use http://guides.rubyonrails.org/
Now in http://guides.rubyonrails.org/active_record_migrations.html there is no option like foreign_key: true.
Even if you pass it, it wont make difference because according to the method add_reference
http://apidock.com/rails/v4.0.2/ActiveRecord/ConnectionAdapters/SchemaStatements/add_reference
It is not expecting foreign_key to be as option.
And lastly add_reference is basically calling http://apidock.com/rails/v4.0.2/ActiveRecord/ConnectionAdapters/SchemaStatements/add_column add_column method in it, which is also not expecting foreign_key to be passed as parameter, so it is not at all necessary.
Hope it makes sense
Actually, you don't need the option if you defined the association on the model. You migration could look like this:
class AddUserRefToProducts < ActiveRecord::Migration
def change
add_column :products, :user_id, :integer
end
end
If the Product model has the association, it should work
class Product < ActiveRecord::Base
belongs_to :user
end
A user has many uploads. I want to add a column to the uploads table that references the user. What should the migration look like?
Here is what I have. I'm not sure if I should use (1) :user_id, :int or (2) :user, :references. I'm not even sure if (2) works. Just trying to do this the "rails" way.
class AddUserToUploads < ActiveRecord::Migration
def change
add_column :uploads, :user_id, :integer
end
end
Relevant question except for Rails 3. Rails 3 migrations: Adding reference column?
Rails 4.x
When you already have users and uploads tables and wish to add a new relationship between them.
All you need to do is: just generate a migration using the following command:
rails g migration AddUserToUploads user:references
Which will create a migration file as:
class AddUserToUploads < ActiveRecord::Migration
def change
add_reference :uploads, :user, index: true
end
end
Then, run the migration using rake db:migrate.
This migration will take care of adding a new column named user_id to uploads table (referencing id column in users table), PLUS it will also add an index on the new column.
UPDATE [For Rails 4.2]
Rails can’t be trusted to maintain referential integrity; relational databases come to our rescue here. What that means is that we can add foreign key constraints at the database level itself and ensure that database would reject any operation that violates this set referential integrity. As #infoget commented, Rails 4.2 ships with native support for foreign keys(referential integrity). It's not required but you might want to add foreign key(as it's very useful) to the reference that we created above.
To add foreign key to an existing reference, create a new migration to add a foreign key:
class AddForeignKeyToUploads < ActiveRecord::Migration
def change
add_foreign_key :uploads, :users
end
end
To create a completely brand new reference with a foreign key(in Rails 4.2), generate a migration using the following command:
rails g migration AddUserToUploads user:references
which will create a migration file as:
class AddUserToUploads < ActiveRecord::Migration
def change
add_reference :uploads, :user, index: true
add_foreign_key :uploads, :users
end
end
This will add a new foreign key to the user_id column of the uploads table. The key references the id column in users table.
NOTE: This is in addition to adding a reference so you still need to create a reference first then foreign key (you can choose to create a foreign key in the same migration or a separate migration file). Active Record only supports single column foreign keys and currently only mysql, mysql2 and PostgreSQL adapters are supported. Don't try this with other adapters like sqlite3, etc. Refer to Rails Guides: Foreign Keys for your reference.
Rails 5
You can still use this command to create the migration:
rails g migration AddUserToUploads user:references
The migration looks a bit different to before, but still works:
class AddUserToUploads < ActiveRecord::Migration[5.0]
def change
add_reference :uploads, :user, foreign_key: true
end
end
Note that it's :user, not :user_id
if you like another alternate approach with up and down method try this:
def up
change_table :uploads do |t|
t.references :user, index: true
end
end
def down
change_table :uploads do |t|
t.remove_references :user, index: true
end
end
Create a migration file
rails generate migration add_references_to_uploads user:references
Default foreign key name
This would create a user_id column in uploads table as a foreign key
class AddReferencesToUploads < ActiveRecord::Migration[5.2]
def change
add_reference :uploads, :user, foreign_key: true
end
end
user model:
class User < ApplicationRecord
has_many :uploads
end
upload model:
class Upload < ApplicationRecord
belongs_to :user
end
Customize foreign key name:
add_reference :uploads, :author, references: :user, foreign_key: true
This would create an author_id column in the uploads tables as the foreign key.
user model:
class User < ApplicationRecord
has_many :uploads, foreign_key: 'author_id'
end
upload model:
class Upload < ApplicationRecord
belongs_to :user
end
Just to document if someone has the same problem...
In my situation I've been using :uuid fields, and the above answers does not work to my case, because rails 5 are creating a column using :bigint instead :uuid:
add_reference :uploads, :user, index: true, type: :uuid
Reference: Active Record Postgresql UUID
[Using Rails 5]
Generate migration:
rails generate migration add_user_reference_to_uploads user:references
This will create the migration file:
class AddUserReferenceToUploads < ActiveRecord::Migration[5.1]
def change
add_reference :uploads, :user, foreign_key: true
end
end
Now if you observe the schema file, you will see that the uploads table contains a new field. Something like: t.bigint "user_id" or t.integer "user_id".
Migrate database:
rails db:migrate
Another syntax of doing the same thing is:
rails g migration AddUserToUpload user:belongs_to
class MigrationName < ActiveRecord::Migration[7.0]
disable_ddl_transaction!
def change
add_reference :uploads, :user, index: {algorithm: :concurrently}
end
end
I would like to add a has_many relationship to two existing tables/models in my app & I'm not too sure how to di it?
When I did this before with a new model the rails generate command handled everything for me, with just rails generate model Photo image:string hikingtrail:references it created the below migration
class CreatePhotos < ActiveRecord::Migration
def change
create_table :photos do |t|
t.string :image
t.references :hikingtrail
t.timestamps
end
add_index :photos, :hikingtrail_id
end
end
Now I would like set up a relationship between users & photos with each user has_many :photos.
When I generate a migration to achieve this it does not include the add_index :photos, :user_id, is this something I should be doing manually or are the below steps enough for setting up this relationship in my database?
rails g migration AddUserIdToPhotos user_id:integer
which creates...
class AddUserIdToPhotos < ActiveRecord::Migration
def change
add_column :photos, :user_id, :integer
end
end
& then run...
rake db:migrate
It is enough to set up your relationship. You can add a index to improve the speed of your record searching. In fact some recommend to put a index to all the foreign keys. But don't worry about this now, i guess you are not going to have that many records to use a index.
If you have already migrated everything and want to add a index make do:
rails g migration AddIndexToUserIdToPhotos
and inside add the index column:
class AddUserIdToPhotos < ActiveRecord::Migration
def change
add_index :photos, :user_id
end
end
I'm wondering how I can add associations to my models. Suppose, I generate two models
rails generate model User
rails generate model Car
Now I want to add an associations so that the models acquire the form
class User < ActiveRecord::Base
has_many :cars
end
class Car < ActiveRecord::Base
belongs_to :user
end
The question is: how to apply this modification by migrations in order to obtain cars_users table in the database? I'm planning to use that table in my code.
belongs_to association expect an association_id column in its corresponding table. Since cars belongs_to user, the cars table should have a user_id column. This can be accomplished 2 ways.
first, you can generate the column when you create the model
rails g model car user_id:references
or just add the user_id after you create the model like Richard Brown's answer. Be careful that if you use integer instead of references, you'd have to create the index yourself.
rails g migration add_user_id_to_cars user_id:integer
then in the generated migration, add
add_index :cars, :user_id
UPDATE:
As Joseph has mentioned in the comments, the need to add the index manually has already been addressed in the current version of Rails. I think it was introduced in Rails 4. You can read more of it in the official Rails guide for migrations. The gist of it is running the following generator
bin/rails g migration add_user_to_cars user:references
will create a migration with a line similar to
add_reference :cars, :user, index: true
This will add a user_id column to the cars table and it will also mark that column to be indexed.
Following #jvnill's explanation in rails 4 (and maybe in rails 3.2 too) you can do it like this too (avoiding the id parts and remembering the exact convetions):
rails g migration AddUserToCar user:references
Which will create the following migration, taking care of both adding the column and index with all correct conventions:
class AddUserToCar < ActiveRecord::Migration
def change
add_reference :cars, :user, index: true
end
end
At the end as always run the migration:
rake db:migrate
View your schema.rb to view the new index and user_id column.
Generate a migration to create the association:
rails g migration AddUserIdToCars user_id:integer
rake db:migrate
Migration file:
class Createuser < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
end
create_table :cars do |t|
t.belongs_to :user, index: true
t.varchar(255) :model
t.varchar(255) :color
end
end
end