Rails Basic Associations

jordy garcia
5 min readMay 18, 2021

--

In this article, I will explain to you more about the basic associations belongs_to and has_many, by using a blog app to explain it!

So let’s create our User model with just a name.

$ rails g model User name

Now we got our User model with a column “name”. It’s time to create our next model, the Post model!

$ rails g model Post title body user:references

We’ve created our Post model with a title, a body and user:references… but what does user:references actually mean? Whenever we create a model, rails automatically creates a unique ID, so when we defined user:references it will also add a user_id column to our posts table. Every time we create a post now it will also associate the ID of the user who created the post.

Now we need to add the associations of those models!

Let’s go to app/models/user.rb file and write.

app/models/user.rbclass User < ApplicationRecord has_many :posts, dependent: :destroyend

I wrote has_many :posts but why? You can see the has_many association as “has many or none” did you understand this? Me neither! Let’s use our models as an example so “One user can have zero posts or many posts”. You can create a User without writing any posts and the user should still exist, right? The user can also create many posts and still exist. So when you compare two models like that and both statements are true this is a has_many relationship. We also wrote :posts in plural that’s because like you could have guested has_many is also plural!

I will explain to you later what “dependent: :destroy” means and why it is so important!

Cool so now we have that out of the way let’s go to our Post model. Navigate to app/models/post.rb file and you can see that rails already wrote something.

app/models/post.rbclass Post < ApplicationRecord  belongs_to :userend

Do you remember how we created our Post model? We added the user:references, when we generated the Post model, that’s why rails know that it probably belongs_to the user.

So let’s break this down! One post cannot have many users, right? Every post only has one user that’s why we write belongs_to :user. You can see that we wrote now “:user” instead of “:users”, that’s because a post belongs to one user so we write it in the singular.

Remember in our User model we wrote after has_many :posts, dependent: :destroy? It is very important as our post model belongs to a user, it will throw us a database error if there would be a post without a user, so we need to destroy all posts created by the user we want to destroy.

Let’s migrate our database and test if it works!

$ rails db:migrate

Let’s open our rails console by writing.

$ rails c

You can see that I wrote “rails c” instead of “rails console” that is because like you probably could have guessed “rails c” is short for “rails console”.

irb(main):001:0> user = User.create(name: "JohnDoe")

I save the user in a variable called user so I could easily find the user back that I have created. Let’s create a post with our user!

irb(main):002:0> user.posts.create(title: "What a great title", body: "I really like how he explains me about all those associations!")

Cool, so now we have a user and a post! we can also find all the user posts by writing.

irb(main):003:0> user.posts

Which will show you all the posts of the user! Remember that you can use this in your views if you want to show all the users posts on their show page! But what if you have an index page showing all the posts created and you need to find the user who created the post? You could write.

\User.find(post.user_id)

But rails got much more handy tools for that which we already implemented! Remember how we wrote in the app/models/post.rb file “belongs_to :user”? Let me show you the proper way how to find the user who wrote the post!

irb(main):004:0> post = Post.first
irb(main):005:0> post.user

You will now see all the details of the user who created the post! But I only want to get the name of the user! Alright, easy peasy lemon squeezy!

irb(main):006:0> post.user.name

Great! So if we can find the post we can find the author as well! Did I say, author? It would be much better to call it author instead of user, right? Of course like always, rails got some magic for that as well! We only have to make a few adjustments and we can call “post.author” instead of “post.user”.

So let’s start by changing our column in our posts table, to do that we need to create a migration.

$ rails g migration RenameUserToAuthorInPosts

This will create a migration file for us which we can find in db/migrate/********_rename_user_to_author_in_posts.rb, let’s navigate there and write this.

db/migrate/********_rename_user_to_author_in_posts.rbclass RenameUserIdToAuthorIdInPosts < ActiveRecord::Migration[6.1]  def change    rename_column :posts, :user_id, :author_id  endend

So as you can see we should modify this file and write rename_column, as we are renaming a column, obviously! Then we write the name of the table we want to modify which is in this case “:posts”, then we write the column we want to rename “user_id”, and finally we write the new name of the column, “author_id”!

Time to migrate our changes!

$ rails db:migrate

Cool so if we check our db/schema.rb file we can see now.

ActiveRecord::Schema.define(version: 2021_05_18_191551) docreate_table "posts", force: :cascade do |t|  t.string "title"
t.string "body"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "author_id", null: false
t.index ["author_id"], name: "index_posts_on_author_id"
endcreate_table "users", force: :cascade do |t| t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
endadd_foreign_key "posts", "users", column: "author_id"end

Do you see that last line “add_foreign_key “posts”, “users”, column: author_id”? That means that our database now knows that the “author_id” is actually “user_id”. The next step is to tell our models that we changed the column name!

Let’s open our app/models/post.rb file and write.

app/models/post.rbclass Post < ApplicationRecord  belongs_to :author, class_name: 'User'end

So now we write belongs_to “:author” and after we write that the actual class_name is “:user”. Now when we write post.author rails will use the author_id to look for the user.

Great so now we know and understand much more about the most used associations. I will write another article about the has_many through association!

So put your fingers on your keyboard and start writing amazing rails apps!

Yay, you know basic associations!

--

--

jordy garcia

Full-Stack Web Developer. Ruby on Rails, React, Redux. JavaScript, Improving open-source projects, one commit at a time.