10: Associating users and content
What’s an association
As in real life, things are very often associated. A person has a pet, a pet has an owner. A book may receive many reviews, that can be associated with only one book.
Adding a migration
To have finer control over the content in our system, we would like to associate each case to its creator.
For this, in our Cases
table we need the additional column called user_id
.
As you probably remember, in order to make structural changes in a table we need a migration. To generate a migration that will add the user_id
column to our Cases
table type in terminal:
$ rails generate migration AddUserIdToCases user_id:integer
Now if you go to /db/migrate/
you will find a file called 123456_add_userid_to_cases.rb
where 123456
will be a random number. Open this file in Sublime Text. It should define an action called change
that will contain the code:
add_column :cases, :user_id, :integer
What it says is that this migration will add a column to the table cases
called user_id
of type integer
(integer means number).
Now we have to make Ruby migrate the table. Save the file and type in the console:
$ rake db:migrate
The belongs_to
association
Having added in our cases
table a user_id
field, that tells to which user the case belongs, we need to also reflect this in the case
model. In /app/models/case.rb
type before end
:
belongs_to :user
Save the file. As you remember a model describes the structure of the rows in a table. The line above specifies that each row in the table cases
belongs to an user
.
The has_many
association
Similarly to how each case
belongs_to
an user
, each user
has_many
cases
. To reflect this, in the user model in /app/models/user.rb
type before end
:
has_many :cases
You might have observed that the user model already had some parameters added to it by Devise.
In practice the same model can have various characteristics. A model could simultaneously belong to something and also have many other things. For example a model explaining a house belongs_to street and house has_many rooms. On facebook, a status belongs_to user and status has_many comments.
The feature of cases belonging to a user and having many updates will be implemented on the second day of the course.
Using the console to associate records
Since we didn't have a user association when the cases were created, the already existing cases do not belong to a user. To correct this in the rails console type:
> u = User.last
> Case.all.each do |c|
> c.user = u
> c.save
> end
This way, we have gone through each case, set its user to the last user in the database and saved it.
The current_user
object
When your app will have many users, the current user logged into our system will not be the user that was last signed up, and thus added to the users table. To find who the current user is, Devise has a handy variable called current_user
.
Associating posts to users
Now that we've manually assigned all the past cases to you, their quickly learning creator, let's make sure that your app will automatically assign the current's user_id
to any newly created case
.
For this we need to edit the create
action in the /app/controllers/cases_controller.rb
by adding the following two lines of code:
@case.user = current_user
@case.save
Displaying the user’s email
Now that the app knows who is the author of each case, we would like to display this information to our users.
As you remember, to display anything we need to show it in a view.
So in /app/views/cases/index.html.erb
edit the list item to:
<li>
<p> <%= "Case id: " + c.id.to_s %> </p>
<p> <%= "Created by: " + c.user.email %> </p>
<p> <%= image_tag(c.image_link ) %> </p>
</li>
What we did was add the case id and the email of the user who created it. The <p> </p>
tags are HTML paragraphs, we added them to have a little more white space around the content. We will remove them when we will get to restyling.
Now, if you save the file, then go to the localhost:3000/cases
page, you will see more information on each case: