Allowing Comments on Ruby on Rails

01
of 07

Allowing Comments

Blogging outdoors on location

lechatnoir/E+/Getty Images

In the previous iteration, Adding RESTful Authentication, authentication was added to your blog so only authorized users could create blog posts. This iteration will add the final (and major) feature of the blog tutorial: comments. After you're finished with this tutorial, users will be able to post anonymous comments on blog posts without logging in.

02
of 07

Scaffolding the Comments

Creating the comments database tables and controller is done much in the same way the posts database tables and controller was created--by using the scaffold generator. The scaffold generator will create RESTful controllers, map routes and create database migrations. But before you take this on, you have to think about what a comment is and what its data members will be. A comment has:

  • Name (required field): The name of the commenter as a string.
  • Email (optional field): The email of the commenter as a string.
  • Body (required field): The body of the comment as text.
  • post: This associates the comment with a particular blog post. This is required for the has_many and belongs_to associations.

Once you've decided what a comment's data members are, you can run the scaffold generator. Note that the post field is of the type "references." This is a special type that will generate an ID field to link the comments table with the posts table via a foreign key.

$ script/generate scaffold comment name:string email:string body:text post:references
exists app/models/
exists app/controllers/
exists app/helpers/
... snip ...

Once the controllers and migrations are generated, you can go ahead and run the migration by running the db:migrate rake task.

$ rake db:migrate
== 20080724173258 CreateComments: migrating ========
-- create_table(:comments)
-> 0.0255s
== 20080724173258 CreateComments: migrated (0.0305s)
03
of 07

Setting up the Model

Once the database tables are in place, you can begin setting up the model. In the model, things like data validations--to ensure required fields are present--and relations can be defined. Two relations will be used.

A blog post has many comments. The has_many relationship doesn't require any special fields in the posts table, but comments table has a post_id to link it to the posts table. From Rails, you can say things like @post.comments to get a list of Comment objects that belong to the @post object. Comments are also dependent on their parent Post object. If the Post object is destroyed, all child comment objects should be destroyed as well.

A comment belongs to a post object. A comment can only be associated with a single blog post. The belongs_to relationship only requires a single post_id field to be in the comments table. To access a comment's parent post object, you can say something like @comment.post in Rails.

The following are the Post and Comment models. Several validations have been added to the comment model to ensure that users fill out the required fields. Note also the has_many and belongs_to relationships.

# File: app/models/post.rb
class Post < ActiveRecord::Base
has_many :comments, :dependent => :destroy
end
# File: app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
validates_presence_of :name
validates_length_of :name, :within => 2..20
validates_presence_of :body
end
04
of 07

Preparing the Comments Controller

The comments controller will not be used in the traditional way a RESTful controller is used. Firstly, it will be accessed solely from the Post views. The comment forms and display are entirely in the show action of the Post controller. So, to start with, delete the entire app/views/comments directory to delete all of the comment views. They won't be needed.

Next, you need to delete some of the actions from the Comments controller. All that's needed is the create and destroy actions. All other actions can be deleted. Since the Comments controller is now just a stub with no views, you have to change a few places in the controller where it attempts to redirect to the Comments controller. Wherever there is a redirect_to call, change it to redirect_to(@comment.post). Below is the complete comments controller.

# File: app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
@comment = Comment.new(params[:comment])
if @comment.save
;flash[:notice] = 'Comment was successfully created.'
redirect_to(@comment.post)
else
flash[:notice] = "Error creating comment: #{@comment.errors}"
redirect_to(@comment.post)
end
end
def destroy
@comment = Comment.find(params[:id])
@comment.destroy
redirect_to(@comment.post)
end
end
05
of 07

The Comments Form

One of the final pieces to put into place is the comments form, which is actually a rather simple task. There are basically two things to do: create a new Comment object in the show action of the posts controller and display a form that submits to the create action of the Comments controller. To do so, modify the show action in the posts controller to look like the following. The added line is in bold.

# File: app/controllers/posts_controller.rb
# GET /posts/1
# GET /posts/1.xml
def show
@post = Post.find(params[:id])
@comment = Comment.new( :post => @post )

Displaying the comment form is the same as any other form. Place this at the bottom of the view for the show action in the posts controller.

06
of 07

Displaying the Comments

The final step is to actually display the comments. Care must be taken when displaying user input data as a user might try to insert HTML tags which could disrupt the page. To prevent this, the h method is used. This method will escape any HTML tags the user tries to input. In a further iteration, a markup language such as RedCloth or a filtering method could be applied to allow users to post certain HTML tags.

Comments will be displayed with a partial, just as posts were. Create a file called app/views/posts/_comment.html.erb and place the following text in it. It will display the comment and, if the user is logged in and can delete the comment, also display the Destroy link to destroy the comment.


says:
:confirm => 'Are you sure?',
:method => :delete if logged_in? %>

Finally, to display all of a post's comments at once, call the comments partial with :collection => @post.comments. This will call the comments partial for every comment that belongs to the post. Add the following line to the show view in the posts controller.

'comment', :collection => @post.comments %>

One this is done, a fully-functional comment system is implemented.

07
of 07

Next Iteration

In the next tutorial iteration, simple_format will be replaced with a more complex formatting engine called RedCloth. RedCloth allows users to create content with easy markup such as *bold* for bold and _italic_ for italic. This will be available to both blog posters and commenters.

Format
mla apa chicago
Your Citation
Morin, Michael. "Allowing Comments on Ruby on Rails." ThoughtCo, Aug. 26, 2020, thoughtco.com/rails-blog-tutorial-allowing-comments-2908216. Morin, Michael. (2020, August 26). Allowing Comments on Ruby on Rails. Retrieved from https://www.thoughtco.com/rails-blog-tutorial-allowing-comments-2908216 Morin, Michael. "Allowing Comments on Ruby on Rails." ThoughtCo. https://www.thoughtco.com/rails-blog-tutorial-allowing-comments-2908216 (accessed March 28, 2024).