AI Reading
Quick summary of this article
Chapter 10: Blog Project Part 2 – Comments and Associations
In Chapter 8 you built a complete blog where you can create, read, update, and delete posts. In this chapter we will make it a realistic application by adding comments. Each comment belongs to a post, which introduces the most important Rails concept after CRUD: associations.
In this chapter you will learn how to connect models with has_many and belongs_to, generate a Comment model, and display and add comments on a post.
🔗 What are Associations?
Associations tell Rails how two models are related. For our blog, a Post has many Comments, and a Comment belongs to a Post. This one-to-many relationship is the foundation of most real applications.
# app/models/post.rb
class Post < ApplicationRecord
has_many :comments, dependent: :destroy
end
# app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :post
end
The dependent: :destroy option means that when a post is deleted, its comments are deleted too, which keeps your database clean.
💾 Generating the Comment Model
Generate a Comment model that belongs to a Post and has a body field:
rails generate model Comment post:references body:text
rails db:migrate
The post:references type automatically adds a post_id column to the comments table and an index on it, which is exactly what the association needs.
# db/migrate/xxx_create_comments.rb
class CreateComments < ActiveRecord::Migration[7.0]
def change
create_table :comments do |t|
t.references :post, null: false, foreign_key: true
t.text :body
t.timestamps
end
end
end
🚀 Creating Comments in the Console
With the association set up, Rails gives you helpful methods. Open the console and try them:
rails console
# Find a post and add a comment to it
post = Post.first
post.comments.create(body: "Great tutorial, thanks!")
# Count comments on the post
post.comments.count
# Find the post a comment belongs to
comment = Comment.first
comment.post.title
Rails automatically fills in the post_id for you when you create a comment through post.comments.create.
📝 Showing Comments in the View
Open app/views/posts/show.html.erb and display the post’s comments by looping over them:
<h3>Comments (<%= @post.comments.count %>)</h3>
<% @post.comments.each do |comment| %>
<p><strong><%= comment.body %></strong></p>
<p><small>Posted on <%= comment.created_at.strftime("%B %d, %Y") %></small></p>
<hr>
<% end %>
✍️ Adding a Comment Form
Add a simple form below the comments list so visitors can leave a new comment:
<h3>Leave a Comment</h3>
<%= form_with model: [ @post, @post.comments.build ] do |form| %>
<div>
<%= form.label :body %><br>
<%= form.text_area :body, rows: 4 %>
</div>
<%= form.submit "Post Comment" %>
<% end %>
For the form to work, add a create action to the controller and a nested route:
# app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.create(comment_params)
redirect_to @post
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
# config/routes.rb
resources :posts do
resources :comments, only: [:create]
end
🏠 Practice Exercises
# 1. Generate the Comment model
rails generate model Comment post:references body:text
rails db:migrate
# 2. Set up the associations
# app/models/post.rb
class Post < ApplicationRecord
has_many :comments, dependent: :destroy
end
# app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :post
end
# 3. Test in the console
post = Post.first
post.comments.create(body: "First comment!")
post.comments.count # => 1
post.comments.map(&:body)
You have now connected two models with a real database relationship. Associations open the door to building applications like a Twitter-style feed, an e-commerce store with orders and line items, or any app where data is related. In the next chapter you will learn how to secure your app with authentication.
