Takor
Takor

Reputation: 277

Routing error while adding comments in my application

I've finished Michael Hartl's "Ruby on Tutorials" book and now I've tried to add comments to microposts but when I tried to post comments, I have an error:

No route matches [POST]

I can't find what is wrong there?

And also I want to know that my associations is correct between models? (I want to create comments like Facebook comments to posts)

comments_controller

class CommentsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]
  before_action :correct_user,   only: :destroy

  def create
    user = User.find_by(params[:id])
    micropost = user.microposts.build(params[:micropost])

    @comment = Comment.new(params[:comment])
    @comment.micropost_id = micropost_id
    @comment.user = current_user

    if @comment.save
      flash[:success] = "Comment created!"
      redirect_to root_url
    else
      render 'static_pages/home'
    end
  end
end

comment.html.erb

<h5>Comments<h5>
<div class="comment">
  <% @user.comments.each do |comment| %>
  <p><%= comment.comment %></p>
  <%= time_ago_in_words(comment.created_at) %> ago.
  <%end%>
</div>

_comment_form.html.erb

<%= form_for :comment do |f| %>
  <%= f.text_area :comment_comment, :size => "40x5", placeholder: "Comment..." %>
  <%= f.submit "Post", class: "btn btn-primary" %>
  <span class="picture">
    <%= f.file_field :picture, accept:'image/jpeg,image/gif,image/png' %>
  </span>
<% end %>

_micropost.html.erb

<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content">
    <%= micropost.content %>
    <%= image_tag micropost.picture.url if micropost.picture? %>
  </span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
    <% if current_user?(micropost.user) %>
      <%= link_to "delete", micropost, method: :delete,
                                   data: { confirm: "You sure?" } %>
    <% end %>
  </span>
  <ol>
    <%= render "comments/comment" %>
  </ol>
  <%= render 'shared/comment_form', micropost: micropost %>
</li>

create_comment.rb

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :comment
      t.references :user, index: true, foreign_key: true
      t.references :micropost, index: true, foreign_key: true
      t.timestamps null: false
    end
    add_index :comments, [:user_id, :micropost_id, :created_at]
  end
end

comment.rb

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :micropost
end

micropost.rb

class Micropost < ActiveRecord::Base
  belongs_to :user
  has_many :comments
end

user.rb

class User < ActiveRecord::Base
  has_many :microposts, dependent: :destroy
  has_many :comments
end

route.rb

resources :microposts, only: [:create, :destroy] do
  member do
    resources :comments, only: [:create, :destroy] 
  end
end

Upvotes: 1

Views: 134

Answers (2)

max
max

Reputation: 102194

This seems very overcomplicated. Creating a nested resource can simply be done like so:

<%= form_for([micropost, micropost.comments.build]) do |f| %>

This will generate the URL /microposts/13/comments for the form action.

Lets fix the route:

resources :microposts, shallow: true, only: [:create, :destroy] do
  resources :comments, only: [:create, :destroy]
end

You should not use member do when nesting resourceful routes in Rails. member and collection are for adding additional methods to a resource beyond the standard CRUD verbs. shallow: true means that rails does not nest the "individual" routes like show, edit, destroy which act on a single resource.

We then clean up the controller:

class CommentsController < ApplicationController

  before_action :set_micropost, only: [:index, :new, :create]

  # POST /microposts/:micropost_id/comments
  def create
    @comment = @micropost.comments.build(comment_params) do |c|
      c.user = current_user
    end

    if @micropost.save
      # ...
    else
      # ...
    end
  end

  def comment_params
    params.require(:comment).permit(:comment_comment, :picture)
  end

  def set_micropost
    @micropost = Micropost.find(params[:micropost_id])
  end
end

Upvotes: 0

akbarbin
akbarbin

Reputation: 5105

You can change your form_for into this

<%= form_for([micropost, micropost.comments.build]) do |f| %>

or

<%= form_for(@comment, :url => micropost_comments_path(micropost.id)) do |f| %>

Then you have to change your routes.rb into:

resources :microposts, only: [:create, :destroy] do
  resources :comments, only: [:create, :destroy]
end

This is example how to create comments in article I hope this help you

Upvotes: 1

Related Questions