This course will be retired on June 1, 2025.
Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Start a free Courses trial
to watch this video
Let's add a Comment model now, and then set up an association so we can add Comments to a Post.
- Let's add a Comment model now. We'll give it a
content
attribute with a type oftext
to hold all the nice things our commenters have to say, and aname
attribute with a type ofstring
so we know who left it.bin/rails g model Comment content:text name:string
- Don't forget to run
bin/rails db:migrate
. That will add acomments
table with ourcontent
column to the database. - Now, we need a
Post
to add comments to.post = Post.last
-
post.comments
fails withNoMethodError: undefined method 'comments' for #<Post...>
- Add
has_many :comments
toPost
.- This takes the symbol you specify,
:comments
, and add a method with that same name to allPost
model objects. - Unlike with the Rails server, though, changes to your code aren't immediately available in the console. We need to
exit
the console first, then restart it withbin/rails c
again.
- This takes the symbol you specify,
- Now we should be able to call our new
comments
method.post = Post.last; post.comments
- Active Record attempts query
SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = ?
- Error:
no such column: comments.post_id
- Active Record attempts query
Active Record is looking for a column in the database that will allow it to associate comments with a Post
. We need to add the appropriate column. But what table should we add it on? The first thing you might attempt is to add several columns to the posts
table, each holding the ID of a record from the comments
table. But you remember the time we considered adding the comment text to the posts
table directly? We rejected that idea because no matter what number of columns we added, it would be too few in some cases, and too many in others. And this setup would give us the same problem.
So instead, we'll add a column on the comments
table, where each record will hold the ID of a record from the posts
table. All the comments with a post_id
of 1
will refer back to the record with an id
of 1
in the posts
table. Comments with a post_id
of 3
will refer back to the post with an id
of 3
. Comments with a post_id
of 7
will refer to the post with an id
of 7
. And so on.
This is a common practice in database design, and is known as adding a foreign key column to a table. The values that a column holds have to match the value of a primary key column, that is, the column that uniquely identifies a record, in a foreign table. In this case, the post_id
field in the comments
table is a foreign key because it refers to values in the id
column of the posts
table, which is that table's primary key. You can learn more about foreign keys in this video.
-
bin/rails generate migration AddPostToComments post_id:integer:index
- The
index
suffix will add anadd_index
method call to the migration.add_index
causes a database table to be indexed by a particular field, in this case thepost_id
field. Now, when we need to look up records with a particularpost_id
in thecomments
table, our database won't have to look through the records one by one. Instead, it will just consult the index, which will point directly to all the records with thepost_id
we're looking for. Whenever you add a foreign key column to a table, you'll usually want to add an index on that column too, for speed's sake.
- The
class AddPostToComments < ActiveRecord::Migration[5.0]
def change
add_column :comments, :post_id, :integer
add_index :comments, :post_id
end
end
-
post = Post.first
(You could also usePost.last
,Post.find
, or any other method that gets you a singlePost
model object.) -
post.comments
returns an empty list right now. - To create a comment that's associated with a post:
comment = post.comments.build
comment.content = "Comment on first post"
comment.name = "Jay"
comment.save
-
post.comments
now returns a list that includes our new comment.
- To create a comment and save it immediately:
post.comments.create(content: "Cool!", name: "Alena")
- Added to list returned from
post.comments
.
- To create and view comments on different post:
post = Post.last
post.comments.create(content: "Comment on last post", name: "Pasan")
Post.last.comments
Post.first.comments
Comment.all
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up