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
...
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 :)
I have 2 models:
Account
Profile
creating these models created 2 tables in the database:
accounts
profiles
now I want to add a relationship:
each account can have many profiles
each profile belongs to one account
I ran the following command:
rails g migration AddAccountToProfiles account:references
which created the following migration:
class AddAccountToProfiles < ActiveRecord::Migration
def change
add_reference :profiles, :account, index: true, foreign_key: true
end
end
now I'm a little confused:
why does the migration say :profiles and :account? Shouldn't it be :accounts (plural)?
also, after (or before) creating this migration, I have to add belongs_to and has_many in the appropriate model class right?
as a side question, is there a way to add belongs_to and has_many in the models, and from that information have rails generate the appropriate migration without me manually creating a migration with the 'rails g migration ...' command?
As per rails documentation, the command
rails g migration AddAccountToProfiles account:references
will generate the migration file below
class AddAccountToProfiles < ActiveRecord::Migration
def change
add_reference :profiles, :account, index: true, foreign_key: true
end
end
Since you specified account:references, then it assumes to create account_id on profiles table, but you still need to add the relationships in the corresponding model files.
When we use :accounts in migration file, it's referring to the table in the database, :account is used as the name of the foreign key to be added onto the table along with suffix _id
Also relevant information here
The migration is correct, because a profile only belongs to one account. It should not be 'accounts'. The migration will place a account_id column onto the profiles table in order to make that connection.
After the migration, you still need to add has_many and belongs_to. In Rails, when defining a relationship, there are generally two steps 1) create the database migration 2) define the relation on the model class itself. You need to have both. In this case, Rails is looking for the account_id column on a profile (the default foreign key) to make the relationship between the two models.
And as for your last question, no, there is not a way to generate migrations after defining a has_many. You can use Rails generators to create the model itself rails generate model ModelName and define the relationship in that model; that will add the correct belongs_to and has_many into the generated model along with the migration. But in practice, it's generally better to create the migration and manually add belongs_to and has_many as needed so there's less of a chance of missing something.
I am having trouble wrapping my head around what I'd consider a more complex association and was hoping someone could help point me in the right direction.
I have four models:
user
profile
feed_group
feed
All 4 of these obviously have their own fields and data stored within. My goal is to have a summary database table called "user_detail" (I am open to calling it something different if Rails has its conventions), which has the following 4 fields:
user_id
profile_id
feed_group_id
feed_id
What would my model associations look like?
Thanks.
You can create the model through a migration like this:
rails g model UserDetail user:references profile:references feed_group:references feed:references
Within the created file models/user_detail.rb you will find the relations:
class UserDetail < ActiveRecord::Base
belongs_to :user
belongs_to :profile
belongs_to :feed_group
belongs_to :feed
end
Also, add references to UserDetail in all the referenced models, eg. in models/user.rb add has_many :user_details, etc.
As I read your question, that's all you need.
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.
Hopefully I don't get flamed for this one too bad - I've tried my very hardest to find an answer to no avail.
I was wondering if someone could help me figure out how to properly declare associations in Ruby on Rails (3). At the moment, I have 3 models:
#room.rb
class Room < ActiveRecord::Base
has_many :check_ins
end
#check_in.rb
class CheckIn < ActiveRecord::Base
belongs_to :user
belongs_to :room
end
#user.rb
class User < ActiveRecord::Base
has_one :check_in
end
So far, I haven't done any migrations to add foreign_key columns to any of my tables (does Rails do this for you?).
I'm confused about why the command CheckIn.first.user returns nil whereas the command User.first.check_in returns SQLite3::SQLException: no such column. The same happens with respect to CheckIn.first.room and Room.first.check_ins, respectively. What would I need to do in order to have User.first.check_in return the CheckIn object associated with the first user and Room.first.check_ins return the set of CheckIns associated with the first Room?
Any help would be GREATLY appreciated.
Charlie
How did you originally generate these models? Did you just make the model files, or did you use rails' model generator (which also generates a migration for you)?
#room.rb
class Room < ActiveRecord::Base
has_many :check_ins
end
#check_in.rb
class CheckIn < ActiveRecord::Base
belongs_to :user
belongs_to :room
end
#user.rb
class User < ActiveRecord::Base
has_one :check_in
has_one :room, :through => :check_in
end
In db/migrations/34612525162_something_something.rb You need to make sure you have migrations that set these tables up for you. The easiest way for you to do it would be to run this command in a console, modify the commands to use the fields you want, the *_id fields are required for your associations to work:
rails generate model user name:string email:string otherfield:integer
rails generate model check_in user_id:integer room_id:integer
rails generate model room number:integer
Note that these will also generate model files for you, since you already have these 3 model files it'll ask you if you want to overwrite them, or skip the files. You can skip them and it should be just fine. If you already had the migrations for part of the data in these models then you can just add the user_id and room_id fields to the check_in model by running this generator instead:
rails generate migration AddIdsToCheckIn user_id:integer room_id:integer
For rails 2.3.x replace rails generate with script/generate. Next you can inspect your migration(s) by opening the files up in db/migrate.rb and modify them there if you need to. Finally, run the migrations:
rake db:migrate
And it should work out for you. Note that I added a has_one, :through => relationship to User - this is so that you can do #user.room without having to make 3 chains: #user.check_in.room
You need to add the migrations yourself (or if you aren't live, you can modify an existing migration). Basically, you need to give the belongs_to side of the relationship a foreign key.
There is absolutely no reason to get flamed don't worry :) It seems here that you are trying to do a one to many association, but you're actually doing a many to many one.
If a user has one check in, it means that he/she has one room. So, you could just have :
user has_one room
room belongs to user
and room has a user_id.
Hope that helps :)