简体   繁体   中英

Ruby on Rails - Adding comments to post

Trying to learn RoR. Currently adding comments to posts by user. So far I have a posts model, comments model and post_comments model (to associate the two). So for in 'rails console' I can run: (say I set p = Post.first and c = Comment.first)

p.comments << c

This forms an association so it works in the console. I just can't seem to get the comments to form this association from the UI. So far I am creating the comments at "comments/new" (not sure if this is the issue. Do they need to be created on the "show view" for "post").

Here are some code snippets

Controllers comments_controller.rb

class CommentsController < ApplicationController

def index
  @comment = Comment.all
end

def new
  @comment = Comment.new
end

def create
  @comment = Comment.new(commentParams)
  if @comment.save
    flash[:success] = "Comment successfully added"
    redirect_to comments_path(@comment)
  else
    render 'new'
  end
end

def show
  @comment = Comment.find(params[:id])
end

private

  def commentParams
    params.require(:comment).permit(:comment)
  end
end

posts_controller

class PostsController < ApplicationController
before_action :setPost, only: [:edit, :update, :show, :destroy, :sold]
before_action :requireUser, except: [:index, :show]
before_action :requireSameUser, only: [:edit, :update, :destroy, :sold]

def index
  @posts = Post.paginate(page: params[:page], per_page: 20)
end

def new
  @post = Post.new
end

def create
  @post = Post.new(postParams)
  @post.user = currentUser
  if @post.save
    flash[:success] = "Post successfully added."
    redirect_to post_path(@post)
  else
    render 'new'
  end
end

def update
  if @post.update(postParams)
    flash[:success] = "Post successfully updated."
    redirect_to post_path(@post)
  else
    render 'edit'
  end
end

def show
end

def edit
end

def sold
  @post.toggle(:sold)
  @post.save
  redirect_to post_path(@post)
end

def destroy
  @post.destroy
  flash[:danger] = "Item successfully deleted."
  redirect_to posts_path
end

private
  def postParams
    params.require(:post).permit(:title, :price, :description,   category_ids:[])
  end

  def setPost
    @post = Post.find(params[:id])
  end

  def requireSameUser
    if currentUser != @post.user and !currentUser.admin
      flash[:danger] = "You can only edit or delete your own items"
      redirect_to root_path
    end
  end
end

Models comment.rb

class Comment < ActiveRecord::Base
  belongs_to :post_comments
  belongs_to :user
  belongs_to :post
end

post_comment.rb

class PostComment < ActiveRecord::Base
  belongs_to :post
  belongs_to :comment
end

post.rb

class Post < ActiveRecord::Base
  belongs_to :user
  has_many :post_categories
  has_many :categories, through: :post_categories
  has_many :post_comments
  has_many :comments, through: :post_comments  

  validates :title, presence: true,
                length: { minimum: 4, maximum: 20 }

  validates :description, presence: true,
                      length: { maximum: 1000 }
  validates :user_id, presence: true

end

Views posts/show.html.erb

  <p>Comments: <%= render @post.comments %></p>

This renders the partial below

comments/_comment.html.erb <%= link_to comment.name, comment_path(comment) %>

Finally is the new comment page as it is.

comments/new.html.erb

<h1>New Comment</h1>

<%= render 'shared/errors', obj: @comment %>

<div class="row">
<div class="col-xs-12">
  <%= form_for(@comment, :html => {class: "form-horizontal", role: "form"}) do |f| %>

  <div class="form-group">
    <div class="control-label col-sm-2">
      <%= f.label :comment %>
    </div>

    <div class="col-sm-8">
      <%= f.text_area :comment, rows: 3, class: "form-control", placeholder: "Please enter a comment", autofocus: true %>
    </div>
  </div>

  <div class="form-group">
    <div class="center col-sm-offset-1 col-sm-10">
      <%= f.submit class: "btn btn-primary btn-lg" %>
    </div>
  </div>
<% end %>

Any help would be greatly received.

Update

Log

Started GET "/posts/2" for ::1 at 2016-01-15 12:39:55 +0000
Processing by PostsController#show as HTML
Parameters: {"id"=>"2"}
[1m[36mPost Load (0.1ms)[0m  [1mSELECT  "posts".* FROM "posts" WHERE    "posts"."id" = ? LIMIT 1[0m  [["id", 2]]
[1m[35mUser Load (0.1ms)[0m  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1  [["id", 1]]
[1m[36m (0.1ms)[0m  [1mSELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = ?[0m  [["user_id", 1]]
[1m[35mCategory Exists (0.1ms)[0m  SELECT  1 AS one FROM "categories"    INNER JOIN "post_categories" ON "categories"."id" =  "post_categories"."category_id" WHERE "post_categories"."post_id" = ?  LIMIT 1  [["post_id", 2]]
[1m[36mCategory Load (0.0ms)[0m  [1mSELECT "categories".* FROM "categories" INNER JOIN "post_categories" ON "categories"."id" = "post_categories"."category_id" WHERE "post_categories"."post_id" = ?[0m  [["post_id", 2]]
Rendered categories/_category.html.erb (0.2ms)
[1m[35mComment Load (0.1ms)[0m  SELECT "comments".* FROM "comments"  WHERE "comments"."post_id" = ?  [["post_id", 2]]
Rendered comments/_comment.html.erb (0.1ms)
Rendered posts/show.html.erb within layouts/application (6.5ms)
[1m[36mCategory Load (0.1ms)[0m  [1mSELECT "categories".* FROM "categories"[0m
Rendered layouts/_navigation.html.erb (0.9ms)
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/_footer.html.erb (0.1ms)
Completed 200 OK in 52ms (Views: 50.3ms | ActiveRecord: 0.5ms)

As a comment can belong to a single post only, you do not need an association table (post_comments). You just need a simple one-to-many relationship.

Your post comment would be:

class Post < ActiveRecord::Base
  has_many :comments
  ...
end

And comment would be like this:

class Comment < ActiveRecord::Base
  belongs_to :post
  ...
end

Just make sure that you have the necessary post_id column in the comments table (you can check the db/schema.rb file). If that is missing, you can use the following migration to add it:

class AddPostIdToComments < ActiveRecord::Migration
  def change
    add_column :comments, :post_id, :integer
    add_index  :comments, :post_id
  end
end

You also need to make sure you keep somewhere the reference to the post, whenever a user tries to create a comment to a post. You can add this in a hidden field to your comments/new.html.erb template. You could set the hidden field in the new action, in PostsController, after passing it through the URL.

So, in your posts/show.html.erb template you would have:

<%= link_to "Add Comment", new_comment_path(post_id: @post.id) %>

In your new action, in PostsController :

def new
  @comment = Comment.new(post_id: params[:post_id])
end

And finally the hidden field in your form would be:

<%= f.hidden_field :post_id %>

Finally, add the post_id parameter to the list of permitted parameters in CommentsController .

instead of

In your new action, in PostsController:

def new
    @comment = Comment.new(post_id: params[:post_id])
end

you can use this in the form views

<%= form.hidden_field :post_id, value: "#{params[:post_id]}" %>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM