Ruby on Rails - Building a Reddit-like Commenting System with Rails - ruby on rails tutorial - rails guides - rails tutorial - ruby rails



What is Reddit?

  • Reddit is a website in which a community of registered users (redditors) submits content.
  • Its format resembles a traditional bulletin board system allowing users to post messages and links to other websites and comment on each other's posts.
  • Entries are ranked by a voting system; other users can vote comments and posts either up (upvoted) or down.
  • Users who post and comment receive "karma" for upvotes and lose karma for downvotes.

Approach:

  • Massive platforms like YouTube and reddit are driven by their threaded commenting features.
  • Reddit as the starting point for this tutorial. Assume your project involves someone submitting a story link to share on the site.
  • Other users can then comment directly on that story, or comment on another user’s comment.
  • To build this, you could also use one model, with one column for “story_id” and one for “comment_id” (meaning one column would always be nil). Or you could use polymorphic associations.
  • With a polymorphic association, we’ll create one Comments model. There will then be one column for “commentable_id”, which will store the ID of the object we’re commenting on, and then “commentable_type”, which will indicate what type of object we’re commenting on (in this case, a Story or a Comment).

Models:

  • we’ll be starting with a brand-new Rails app (using Rails 4). We’re only going to add what we need to demonstrate this feature, so for starters, let’s create the stories model.
  • This is what users submit to our Reddit-like site, so it’s just a Title and URL (that the title would link out to).
rails g model story title:text url:string
rake db:migrate
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • So now we have the objects that make the core of our user experience.
  • We decided to use “text” for the title, so we’re not limited by length (string is limited to 255 characters). Now let’s add the model for comments.
rails g model comment body:text commentable_id:integer commentable_type:string
rake db:migrate
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Now that we have these two models created, we need to create the associations between them.
  • The easiest place to start is with Stories. A story can have many comments, so we need to add that.
  • However, Rails would normally assume that comments would include a column called “story_id” which it doesn’t so we need include the name we gave to the polymorphic association:

app/models/story.rb

class Story < ActiveRecord::Base
  has_many :comments, as: :commentable
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

apps/models.comment.rb

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
  has_many :comments, as :commentable
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • So, to recap, a Story can have many comments. A Comment can have many comments.
  • And since a comment can belong to more than one model, we specify that a comment belongs to a polymorphic association through commentable.
  • Now let’s see how this works. Fire up your trusty Rails console:
rails c
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Since we have no entries in our database for our Reddit-like site, let’s create one:
Story.create(title: "Live 1:1 help from expert developers", url: "http://www.codementor.io")
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • You should then see this entry be created:
INSERT INTO "stories" ("title", "url", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "Live 1:1 help from expert developers"], ["url", "http://www.codementor.io"], ["created_at", "2016-01-11 22:02:54.637379"], ["updated_at", "2016-01-11 22:02:54.637379"]]
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • We then want to add a comment to that story, to make sure our associations work properly.
  • Let’s enter it through the comments association with the story, to mimic if we were to leave a comment on a story on the story’s show page.
  • We can just use Story.first since it’s the only entry in our database.
Story.first.comments.create(body: "What a helpful resource!")
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

And we should see the following:

INSERT INTO "comments" ("body", "commentable_id", "commentable_type", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["body", "What a helpful resource"], ["commentable_id", 1], ["commentable_type", "Story"], ["created_at", "2016-01-11 22:08:03.701599"], ["updated_at", "2016-01-11 22:08:03.701599"]]
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • You’ll see that Rails knew that the commentable_type was Story, since it was a comment on a story, and that it used the story_id (1, since this was our first entry) as the commentable_id.
  • Now let’s add a comment to that first comment, creating our first threaded/nested comment.
  • We could do it the same way:
Comment.first.comments.create(body: "I agree, very helpful!")
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • And we should see the following:
INSERT INTO "comments" ("commentable_id", "commentable_type", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["commentable_id", 1], ["commentable_type", "Comment"], ["body", "I agree, very helpful"], ["created_at", "2016-01-11 22:33:35.018312"], ["updated_at", "2016-01-11 22:33:35.018312"]]
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

Routes:

  • As the traffic cop for Rails, we have to tell our routes.rb what to do with web requests.
  • First we’ll tell the app to use the index page for stories as the root for this site. Then we’ll add the resources for stories and comments.
  • This will create all of the default actions (index, show, new, edit, create, update and destroy) for each controller.
  • But to each, we’ll also add a nested resource, to nest those actions for comments within each set of routes. So it looks like this:

config/routes.rb

Rails.application.routes.draw do
  root 'stories#index'

  resources :stories do
    resources :comments
  end

  resources :comments do
    resources :comments
  end

end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Let’s see if everything is routing correctly. Since we didn’t limit the default routes, we’ll see more than we need (for instance, we won’t have a comments Index page), but this will help you see how it’s all nested. In the Terminal, check your routes with:
rake routes
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • This is what you should see:
Prefix Verb   URI Pattern                                       Controller#Action
                root GET    /                                                 stories#index
      story_comments GET    /stories/:story_id/comments(.:format)             comments#index
                     POST   /stories/:story_id/comments(.:format)             comments#create
   new_story_comment GET    /stories/:story_id/comments/new(.:format)         comments#new
  edit_story_comment GET    /stories/:story_id/comments/:id/edit(.:format)    comments#edit
       story_comment GET    /stories/:story_id/comments/:id(.:format)         comments#show
                     PATCH  /stories/:story_id/comments/:id(.:format)         comments#update
                     PUT    /stories/:story_id/comments/:id(.:format)         comments#update
                     DELETE /stories/:story_id/comments/:id(.:format)         comments#destroy
             stories GET    /stories(.:format)                                stories#index
                     POST   /stories(.:format)                                stories#create
           new_story GET    /stories/new(.:format)                            stories#new
          edit_story GET    /stories/:id/edit(.:format)                       stories#edit
               story GET    /stories/:id(.:format)                            stories#show
                     PATCH  /stories/:id(.:format)                            stories#update
                     PUT    /stories/:id(.:format)                            stories#update
                     DELETE /stories/:id(.:format)                            stories#destroy
    comment_comments GET    /comments/:comment_id/comments(.:format)          comments#index
                     POST   /comments/:comment_id/comments(.:format)          comments#create
 new_comment_comment GET    /comments/:comment_id/comments/new(.:format)      comments#new
edit_comment_comment GET    /comments/:comment_id/comments/:id/edit(.:format) comments#edit
     comment_comment GET    /comments/:comment_id/comments/:id(.:format)      comments#show
                     PATCH  /comments/:comment_id/comments/:id(.:format)      comments#update
                     PUT    /comments/:comment_id/comments/:id(.:format)      comments#update
                     DELETE /comments/:comment_id/comments/:id(.:format)      comments#destroy
            comments GET    /comments(.:format)                               comments#index
                     POST   /comments(.:format)                               comments#create
         new_comment GET    /comments/new(.:format)                           comments#new
        edit_comment GET    /comments/:id/edit(.:format)                      comments#edit
             comment GET    /comments/:id(.:format)                           comments#show
                     PATCH  /comments/:id(.:format)                           comments#update
                     PUT    /comments/:id(.:format)                           comments#update
                     DELETE /comments/:id(.:format)                           comments#destroy
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Success again! You’ll see there are stories, there are comments, then there are comments nested within stories, and comments nested within comments.
  • Now that the requests are going where they need to go, let’s make sure we’re providing the proper response for each.

Controllers:

  • As we’re dealing with stories and comments, we’ll need to create a controller for each. We’ll start with stories.
  • For the sake of brevity in this tutorial, we’re going to skip creating, editing, or deleting stories, since we have at least one to already work with.
  • So we’ll just handle the index and show requests, so that we can view the story we created. Notice that we don’t have to address comments at all here.

app/controllers/stories_controller.rb

class StoriesController < ApplicationController
  def index
    @stories = Story.all
  end

  def show
    @story = Story.find(params[:id])
  end
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Now we move onto the comments controller. Here we don’t need index and show, as comments always live on story view pages, and don’t have their own pages.
  • But we’ll need new and create, because we want to create new comments.
  • We also need to create a method to let Rails know if we’re creating a comment for a story or for a comment.

app/controllers/comments_controller.rb

class CommentsController < ApplicationController
before_action :find_commentable

    def new
      @comment = Comment.new
    end

    def create
      @comment = @commentable.comments.new comment_params

      if @comment.save
        redirect_to :back, notice: 'Your comment was successfully posted!'
      else
        redirect_to :back, notice: "Your comment wasn't posted!"
      end
    end

    private

    def comment_params
      params.require(:comment).permit(:body)
    end

    def find_commentable
      @commentable = Comment.find_by_id(params[:comment_id]) if params[:comment_id]
      @commentable = Story.find_by_id(params[:story_id]) if params[:story_id]
    end

end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Since our comments are nested within other comments or stories, we’re using the instance variable @commentable in the create action.
  • We have a private method (find_commentable) that is telling Rails that if the params contains a comment_id, it’s a comment on a comment, and if it has story_id, it’s a comment on a story.
  • We then added a filter at the top of the controller, telling Rails to run the private method before performing any other action (otherwise it wouldn’t know what @commentable was when it got to the create action).
  • Lastly, we need to create the views to see all this magic we created work.

Views:

  • There are four elements we need for all of this to work.
  • We need a show page for a story, and index page for stories, a way to see comments, and a way to post comments.
  • Let’s start with the index page and show page.
  • The index page will display all of the stories in our database, along with a link to the show page for each story.

app/views/stories/index.html.erb:

<h1>Stories</h1>
<% @stories.each do |story| %>
  <p>
    <%= link_to(story.title, story.url, target: "_blank") %> - <%= link_to("Show Page", story) %>
  </p>
<% end %>
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Now we need the show page for each story. Inspired by a show page on reddit, this page will have details about the story, a form for submitting a comment about the story, the display of each comment, and the ability to comment on a comment.

app/views/stories/show.html.erb

<%= link_to(@story.title, @story.url, target: "_blank") %><br/>
<small>Submitted <%= time_ago_in_words(@story.created_at) %> ago</small>

<h3>Comments</h3>

<%= form_for [@story, Comment.new] do |f| %>
<%= f.text_area :body, placeholder: "Add a comment" %><br/>
<%= f.submit "Add Comment" %>
<% end %>

<ul>
  <%= render(partial: 'comments/comment', collection: @story.comments) %>
</ul>
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • You’ll see that we broke out some elements into a partial. So, we need to add that view file.

apps/views/comments/_comment.html.erb

<li>
  <%= comment.body %> -
  <small>Submitted <%= time_ago_in_words(comment.created_at) %> ago</small>

  <%= form_for [comment, Comment.new] do |f| %>
      <%= f.text_area :body, placeholder: "Add a Reply" %><br/>
      <%= f.submit "Reply"  %>
      <% end %>

  <ul>
      <%= render partial: 'comments/comment', collection: comment.comments %>
  </ul>

</li>
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Because we’re passing this partial the collection of comments, it displays each comment and the form for replying to that comment.
  • But then it renders itself within itself (recursive!), to display the replies each comment might have.
  • And by using the ul/li structure, we’re making sure they all nest correctly when they display. Fancy.

See Our Handiwork in Action:

  • Fire up the server, and take a look at what we did.
rails s 
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Because we created a story, a comment, and a reply already, so you should see them all.
  • Then play around with adding a new comment on that story, and then a reply to that comment.
  • If you add the new and create actions and new view to Stories, you will basically have the core functionality of reddit built.

This ruby on rails tutorial page provides you the following key areas such as ruby , rail , ruby on rails , rail forum , ruby on rails tutorial , ruby tutorial , rails guides , rails tutorial , learn ruby , rails form_for , ruby rails , ruby class , what is ruby on rails , rails installer , ruby online , learn ruby on rails , ruby on rails jobs , rails find_by , install rails , easyrail , rubyonrails , link_to rails , ruby on rails developer , learn ruby the hard way , railscasts , ruby on rails examples , ruby on rails vs php , rails 4 , rails activerecord , rails generate , ruby and rails , ruby on rails download , install ruby on rails , ruby net http , what is rails , ruby app , ruby vs ruby on rails , ruby on rails windows , rails for zombies , ruby on rails book , ruby on rails development , ruby on rails ide , ruby on rails tutorial pdf

Related Searches to Building a Reddit-like Commenting System with Rails