Pregunta

I've tried every commenting gem out there and they pretty much all suck.

Take a look at this question I previously asked:Finding user total votes recieved on posts by other users

Per recommendation, I've decided to build my own commenting system from scratch.

Here is the goal:

To have a post model, user model(using devise), comment model.

The users can create comments. These comments are votable. The amount sum of votes users receive on the comments they made is their score or karma.

How do I implement something like this?

So far this is what I have:

I ran

rails generate model Comment commenter:string body:text post:references

The migration

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.string :commenter
      t.text :body
      t.references :post

      t.timestamps
    end

    add_index :comments, :post_id
  end
end

In my comment model

class Comment < ActiveRecord::Base
  belongs_to :post
  attr_accessible :commenter, :body
end

In my post model

class Post < ActiveRecord::Base
  has_many :comments
end

My routes file

resources :posts do
  resources :comments
end

My comments controller

class CommentsController < ApplicationController
  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.create(params[:comment].permit(:commenter, :body))
    redirect_to post_path(@post)
  end
end

Within my posts show view

<h2>Comments</h2>
<% @post.comments.each do |comment| %>
  <p>
    <strong>Commenter:</strong>
    <%= comment.commenter %>
 </p>

 <p>
   <strong>Comment:</strong>
   <%= comment.body %>
 </p>

<% end %>

<%= form_for([@post, @post.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br />
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br />
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
 <% end %>

<%= link_to 'Edit Post', edit_post_path(@post) %> |
<%= link_to 'Back to Posts', posts_path %>

I really need help here: Instead of picking a commenter name, I need the controller to require the user to be logged in, and pass the current user as the commentor of the comment. How do I implement in place editing of a comment?

I then need to use either one of these gems to make the comments votable:

https://github.com/bouchard/thumbs_up

https://github.com/ryanto/acts_as_votable

Lastly I need to be able to calculate the total votes a given user has received on all of their posted comments. Something like @user.comments.votes.size

¿Fue útil?

Solución

To handle assigning the current_user to the comment, first you'll need to change the commenter column to an id that references Users (I would also rename it to commenter_id). So, you'll want to generate the model like so:

rails generate migration ChangeCommentsCommenterToCommenterId

# db/migrate/<timestamp>_change_comments_commenter_to_commenter_id.rb
class ChangeCommentsCommenterToCommenterId < ActiveRecord::Migration
  def change
    remove_column :comments, :commenter
    add_column :comments, :commenter_id, :integer, null: false
    add_index :comments, :commenter_id
  end
end

Or, regenerate the model from scratch:

rails generate model Comment commenter_id:integer:index body:text post:references

Note that I've added an index to the column. In your Comment model:

# app/models/comment.rb
class Comment < ActiveRecord::Base
  belongs_to :post
  belongs_to :commenter, class_name: 'User'
  attr_accessible :body
end

Note that, since we're using belongs_to here, when you send the commenter message to an instance of Comment, you'll get back an instance of User.

Next you'll need to update your controller to make the proper user assignment. I would also recommend a bit of refactoring to private methods to make the implementation more expressive of the domain:

# app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    post.comments.create(new_comment_params) do |comment|
      comment.commenter = current_user
    end
    redirect_to post_path(post)
  end

  private

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

  def post
    @post ||= Post.find(params[:post_id])
  end
end

Since you're redirecting to post_path, I've assumed that you don't need to keep the @comment instance variable.

Finally, you'll want to remove the commenter field from the form in the view. Does that do the trick?

[EDIT: Adding this section to address the question about voting...]

I'm not completely clear on exactly what parts of the voting you're looking for help with, but at least from a high-level perspective, I'd guess you'd probably want a VotesController that's accessible from a nested route:

# config/routes.rb
...
resources :comments do
  resources :votes, except: :index
end

Hope this helps!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top