rails creating relationships between 2 existing models - ruby-on-rails

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.

Related

Setting links between tables in sqlite3. Rails 5

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
...

has_many, belongs_to relation in active record migration rails 4

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.

Ruby on Rails: User model association applications and migrations

I'm still fairly new to Ruby on Rails and I'm working with associations, such as if a table has_many :facts, or belongs_to :list,
do we deal with users as well? for Users model:
has_many :lists
and then the list model should have
belongs_to :user
Now does this mean I need to create a new column in the table? Right now I only have email and password_digest. Do I need to add a new migration to add a new column list_id. I already did rake db:migrate. Can I just simply add a column in the migration file?
Thanks
Yes, you must create a new column and if you already run the migration you must create a new one.
However, it's the list that must have the user_id.

Update database struct when Rails association changes

Which is the best way to do database migration when association changes?
For example:
Add has_one/ has_many/ & belongs_to association to 2 models have no association.
Add has_many_and_belongs_to association to 2 models have no association.
Add has_one/ has_many/ & belongs_to association to 2 models that one model have association with other model, another model is newly created.
When your association changes, is it not just that you have to change the foreign keys in the db scheme and create specific migrations for that?
For example if you want to add a has_many relationship to store which has many books. You could easily create a migration with the generate command.
rails g migration addStoreIdToBooks store_id:integer
Then in your model/store.rb
has_many :books
And in the model/book.rb
belongs_to :store
Otherwise I didn't understand your question :)

Declaring associations in Ruby on Rails

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 :)

Resources