Skip to content

26 Creating Comments

Dave Strus edited this page Jul 16, 2015 · 1 revision

We must have comments! We'll use a gem to do the heavy lifting, rather than building a commenting system from scratch. The gem in question: acts_as_commentable_with_threading.

Let's add it to our Gemfile, install the bundle, and restart the server.

Gemfile

gem 'acts_as_commentable_with_threading'
$ bundle

AACWT (as we'll abbreviate it) can generate a migration and a Comment model for you.

$ bin/rails generate acts_as_commentable_with_threading_migration
      create  db/migrate/20141106191339_acts_as_commentable_with_threading_migration
      create  app/models/comment.rb
$ bin/rake db:migrate
== 20141106191339 ActsAsCommentableWithThreadingMigration: migrating ==========
-- create_table(:comments, {:force=>true})
   -> 0.0082s
-- add_index(:comments, :user_id)
   -> 0.0018s
-- add_index(:comments, [:commentable_id, :commentable_type])
   -> 0.0021s
== 20141106191339 ActsAsCommentableWithThreadingMigration: migrated (0.0124s) =

To allow comments on posts, we add one line of code to the model.

app/models/post.rb

  acts_as_commentable

Restart your Rails console, and let's try adding a comment.

Pick a post, and pick a user. (I've truncated the console output in the following examples.)

[1] pry(main)> post = Post.first
[2] pry(main)> user = User.last

Then build a comment.

[3] pry(main)> comment = Comment.build_from(post, user.id, "First! LOLOLOL")

Now save the comment.

[4] pry(main)> comment.save

Try loading the comment from the post.

[5] pry(main)> post.comment_threads

Does it work? That's worth an incremental commit.

$ git add .
$ git commit -m "Configure acts_as_commentable_with_threading."

In order to create comments in the app, we'll need a route for comments#create. We can nest that route under the existing routes for posts.

config/routes.rb

  resources :comments, only: :create

Let's add a comment form to our view, below our post partials.

app/views/posts/show.html.erb

  <% if user_signed_in? %>
    <%= form_for @comment, html: { class: 'comment' } do |f| %>
      <fieldset>
        <%= f.label :body, 'Add a comment' %><br />
        <%= f.text_area :body %>
      </fieldset>
      <%= f.hidden_field :commentable_type %>
      <%= f.hidden_field :commentable_id %>
      <%= f.submit class: 'btn btn-default' %>
    <% end %>
  <% end %>

Notice that I added a CSS class to the form itself, and I specified the text for the label. I also included hidden fields for commentable_type and commentable_id. AACWT implements Comment with polymorphic relationships to other objects. You're encouraged to learn more about polymorphic relationships.

Now let's add a wee bit of CSS.

app/assets/stylesheets.scss

form.comment {
  fieldset {
    background-color: transparent;
    label {
      font-size: small;
    }
  }
}

We need to build @comment in the controller before the form is rendered.

app/controller/posts_controller.rb

  def show
    @post = Post.find params[:id]
    @comment = Comment.build_from(@post, current_user.id, '') if user_signed_in?
  end

We'll need a CommentsController to actually create comments.

app/controllers/comments_controller.rb

class CommentsController < ApplicationController
  def create
    post = Post.find params[:comment][:commentable_id]
    comment = Comment.build_from post, current_user.id, comment_params[:body]
    if comment.save
      flash[:notice] = 'Your comment has been added.'
    else
      flash[:error] = 'There was a problem adding your comment.'
    end
    redirect_to post
  end

  private

  def comment_params
    params.require(:comment).permit(:body, :commentable_name, :commentable_id, :commentable_type)
  end
end

Try adding a comment to a text post. Use the console to check that the comment saved. If all is well, let's commit our work.

$ git add .
$ git commit -m "Create comments on posts."