I am having some trouble finding a good answer to my question on rails relationship creation.
If I already ran the initial migration for my user model and my comment model Without declaring a relationship (ie: a user has_many comments, and comments belong_to user) how do I define that relationship later on?
Can I simply:
1-add the user_id column to Comments,
2-declare the relationship and
3-run the new add_user_id_to_comment migration file?
Will this work? If not, how would I go about changing the relationship after already having ran the initial migration for the models? Thank you so much for your help.\
Rails 3.1, Ruby 1.8.7
You can just add the reference in another migration, using the change_table migration (documentation):
change_table :comments do |t|
t.references :user
end
Then just add the associations to your models.
class User < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :user
end
Related
It's my first time using Rails and I'm not finding exactly how to generate new models (and migrations) with associations. For example, I have two entities:
Blog
Post
One blog can have many posts, and one post belongs to one blog. I'm using the following commands:
rails generate model Blog /* properties... */ post:has_many
rails generate model Post /* properties... */ blog:belongs_to
But it doesn't work at all (read: the migration and model files are not being generated with the associations). Maybe I'm doing something wrong. Should I create the associations only after I create all my models?
Also, is there a need to declare in both models the relationship, or just in one of them?
Thank you.
When passed as a generator argument belongs_to in is just an alias of references which tells rails to create a column named blog_id which is a foreign key:
# rails generate model Post blog:belongs_to
class CreatePosts < ActiveRecord::Migration[5.0]
def change
create_table :posts do |t|
t.belongs_to :blog, foreign_key: true
t.timestamps
end
end
end
This is the actual database column that defines the relation between two tables.
It also adds the association to the model:
class Post < ApplicationRecord
belongs_to :blog
end
Why does'nt the same work for has_many?
The arguments for the model generators are attributes of the model. blog_id is an actual attribute backed by a database column.
has_many is not an attribute. It's a metaprogramming method which adds a posts method to your Blog instances. You need to add it manually to the model.
If you run rails g model Blog posts:has_many foo:bar Rails will actually create a migration with those attributes:
class CreateBlogs < ActiveRecord::Migration[5.0]
def change
create_table :blogs do |t|
t.has_many :posts
t.bar :foo
t.timestamps
end
end
end
Rails does not type check the arguments. Of course the migration won't actually run:
undefined method `has_many' for #<ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition:0x007fd12d9b8bc8>
If you have already generated the migration just remove the line t.has_many :posts and add has_many :posts to app/models/blog.rb.
For the belongs_to relationship you could use:
rails generate model Post /* properties... */ blog:references
I don't think you have anything for has_many relationship since when you're generating the model and table, you don't have to include anything special there. The relationship is in the "belonging" table.
So for that you just use a simple:
rails generate model Blog /* properties... */
And then manually add the has_many :posts in the model afterward :)
Sorry maybe for the stupid question but I'm new. When I create tables using this command rails g model Post title:string description:text. How can I further make a connection between another table by?
Or will have enough in the models table select belongs_to? And thus the connection will be already established and you will not need to install anything in the migration.
If you want to "connect" the posts table (Post model), with whatever you already have, like a users table, to make an one-to-many association you can use the references as a kind of type, which will generate an entry on the migration file for creating a foreign key column on your (posts) table.
create_table :posts do |t|
t.references :user
...
end
So the command could be:
$ rails generate model Post title:string description:text user:references
There I'm using user as an example, it can be any other.
The model generated will already have the belongs_to association specified, like:
class Post < ApplicationRecord
belongs_to :user
...
What you need then is to add the has_many association in the User model:
class User < ApplicationRecord
has_many :posts
...
I'm working with Rails, and when setting up some tests I encountered:
ActiveModel::MissingAttributeError:
can't write unknown attribute `group_id`
I'm guessing the issue is in my relations. I have
class Group < ActiveRecord::Base
has_many :transactions
has_many :users
end
And
class Transaction < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
And lastly,
class User < ActiveRecord::Base
belongs_to :group
has_many :transactions
end
I saw that someone had the same error because they were using has_one rather than belongs_to and needed to add an ID column to their DB. I'm using belongs_to though, so I don't think that's what I need? Any ideas?
Looks like you don't have the group_id column in your db.
You must remember that Rails is built on top of a relational database, which means that you can access "related" data by referencing a foreign_key.
When setting up a belongs_to / has_many association, the belongs_to table needs to have the appropriate foreign key (in your case group_id):
Your error doesn't state which model you're receiving the exception for; I would hazard a guess that it's User or Transaction.
--
To fix it, I would recommend creating a migration to add the group_id attribute to the appropriate model:
$ rails g migration AddGroupId
#db/migrate/add_group_id____________.rb
class AddGroupID < ActiveRecord::Migration
def change
add_column :users, :group_id, :integer
end
end
$ rake db:migrate
Unless you created the model you are referring to with a migration that had references, you will still need a migration in your database. An easy way to check if the database has one is to visit your some_project_root/db/schema.rb. If you don't see a the field you want there then you will have to generate one. The way you would do so is to run a rails g migration AddXidToY x_id:integer . It should set a field up for the id in the table you want.
I would like to understand the process which can be followed to create models and migrations which in turn create a joining table within the database to resolve a many-to-many relationship. For instance. If i have a course table, a students table and i want to create a joining table called studies with the id from course and students along with extra data such as the grade and date started. Exactly What is the process for doing this?
If i am to use the generate model command for each of the above 3 table names, this will create a separate migration for all of them. Even if i go into the models and add the relevant associations this will not affect how the database is created? Please could you give me some guidance on what steps i must take in order to create the required foreign key relationships here with some examples?
Use a has_many :through association. Set it up manually.
Step 1: Generate your models separately. The joining model Study will contain foreign keys, so remember to include the columns.
rails g model Course title:string
rails g model Student name:string
rails g model Study course_id:integer student_id:integer start_date:date grade:string
Step 2: Set up associations:
# models/course.rb
class Course
has_many :studies
has_many :students, through: :studies
end
# models/student.rb
class Student
has_many :studies
has_many :courses, through: :studies
end
# models/study.rb
class Study
belongs_to :course
belongs_to :student
end
Step 3: Run migrations, restart server (if necessary), and that's it. Rails will handle the rest.
Accessing attributes in the joining table may require careful timing to ensure the correct object is being accessed, since the joining object is not returned via Rails' built-in methods, ie #course.students. Check out this answer for some ideas.
Read the guide for more information.
for many-to-many relationships use:
class Car < ActiveRecord::Base
has_and_belongs_to_many :tires
end
class Tire < ActiveRecord::Base
has_and_belongs_to_many :cars
end
Then you create a migration like this:
class CreateCarsAndTires < ActiveRecord::Migration
def change
create_table :cars do |t|
t.string :name
end
create_table :tires do |t|
t.string :something
end
create_table :cars_tires do |t|
t.belongs_to :car
t.belongs_to :tire
t.string :additional_dataA //optional
t.int :something_else //optional
end
end
end
It is very important that you name your join table in the migration in alphabetical order (c in cars comes before t for tires) as ActiveRecord will look in has_many_and_belongs_to relations for a table which is named this way pluralized-classA_pluralized_classB like apples_bananas vs bananas_apples which would not work and you would have to add the table name to your classes and it goes against the convention over configuration paradigm.
Hope it helps.
I have a User model and a Task model. I have not mentioned any relation between them while creating them.
I need to establish that User has_many Tasks and a Task belongs_to User through a migration
What would be the migration generation command for establishing that relationship?
You could call:
rails g model task user:references
which will generates an user_id column in the tasks table and will modify the task.rb model to add a belongs_to :user relatonship. Please note, you must to put manually the has_many :tasks or has_one :task relationship to the user.rb model.
If you already have the model generated, you could create a migration with the following:
rails g migration AddUserToTask user:belongs_to
which will generate:
class AddUserToTask < ActiveRecord::Migration
def change
add_reference :tasks, :user, index: true
end
end
the only difference with this approach is, the belongs_to :user relationship in the task.rb model won't be created automatically, so you must create it for your own.
To answer the question, "What would be the migration generation command for establishing that relation?"( Meaning, how do you add a migration for existing models with a relationship like User has_many Tasks & Task belongs_to User)
The the easiest way for me to remember is like this:
>rails g migration AddUserToTask user:belongs_to
or
>rails g migration AddUserToTask user:references
:belongs_to is just an alias of :references, so either will do the same thing.
Doing it this way, the command will infer the name of the table from the migration name, set up a change method that will add the column for relationship, and configure it to be indexed:
class AddUserToTask < ActiveRecord::Migration
def change
add_reference :tasks, :user, index: true
end
end
After generating that you:
>rake db:migrate
Finally, you still have to add the usual relations to your models, as is stated in the other answers, but I think this is the right answer to your question.
This is how the migration should be created normally:
rails g scaffold child parent:references
I forgot to add parent:references when I created the table, what should I do?
Option 1: Destroy the table and start over
If you don't have a lot defined in the model/db about the child table. Your best bet might just be to run rails destroy scaffold child, and then run
rails g scaffold child parent:references over it. Be sure to add the line drop_table :children if table_exists? :children before create table in the file that creates the new table. (That way if anyone pulls your code they can just run the migrations and be done.) However, it seems more probable that you will have data you don't want to lose in the child model already.
In that case:
Option 2: Write a migration to add the references
rails g migration add_parent_refs_to_child
## XXXXXXXXXXXXXX_add_parent_refs_to_child.rb
class AddParentRefsToChild < ActiveRecord::Migration
def change
add_reference :child, :parent, index: true
end
end
See add_reference
Additionally, don't forget to make sure the parent model has_[one | many] :children, and that the child model belongs_to :parent.
How not to do it:
You may be tempted to add the parent_id manually. Don't. Conventionally this sort of operation is handled through a migration, or within the initial table creation. Manual addition will detract from the maintainability of the project.
The Ruby on Rails guide to association has more information on the subject.
There is no special migration command that would be used.
In your User model you will put
class User < ActiveRecord::Base
has_many :tasks
end
class Task < ActiveRecord::Base
belongs_to :user
end
In the corresponding migration file for the tasks you have the following field added user_id
Take a look at this guide
The migration will add the user's id to the task table so they know about each other
rails g migration AddUserIdToTask user_id:integer
then
rake db:migrate
And after update your controllers and views so that tasks can't be created on their own but must correspond to a user
The Relationship in Rails is taken care by model not by Rails.
So you just need to define this relationship in your model:
class User < ActiveRecord::Base
has_many :tasks
end
class Task < ActiveRecord::Base
belongs_to :user
end
And just make sure that a user_id field is present in the migration for creating the "tasks" table.