create comments for nested routes - ruby-on-rails

I'm trying to make a blog which has users, posts and comments. Each user can have many posts and many comments similarly each post can have many comments. I have successfully made the user and post sections but am having difficulty creating comments and then displaying them.
code:
routes.rb :
resources :users do
resources :posts do
resources :comments
end
end
user.rb :
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
post.rb :
belongs_to :user
has_many :comments, dependent: :destroy
comment.rb :
belongs_to :post, :user
I'm creating and displaying comments in the post's view itself so..
posts_controller.rb :
def show
#user = current_user
#post = Post.find(params[:id])
end
view/posts/show.html.erb :
<p><strong>Title:</strong><%= #post.title %></p>
<p><strong>Text:</strong><%= #post.text %></p>
<% if #user.posts.comments.empty? %>
<h2>Comments</h2>
<%= render #posts.comments %>
<% end %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<%= link_to 'Edit Post', edit_user_post_path(#user.id,#post) %> |
<%= link_to 'Back to Posts', user_posts_path(#user.id) %>
comments_controller.rb :
class CommentsController < ApplicationController
def create
#user = current_user
#post = #user.posts.find(params[:post_id])
#comment = #user.posts.comments.create(params[:comment])
redirect_to user_post_path(#user.id,#post)
end
def destroy
#user = current_user
#post = #user.posts.find(params[:post_id])
#comment = #user.posts.comments.find(params[:id])
#comment.destroy
redirect_to user_post_path(#user.id,#post)
end
end
And the partials are:
views/comments/_form.html.erb :
<%= form_for([#user,#post,#comment]) do |f| %>
<p>
<%= #user.email %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
I think my form_for is not right here but I'm new to rails and I've also tried form_for(#user,#post,#post.comments.build) but that didn't work either.. Anyways here's another partial:
views/comments/_comment.html.erb:
<p><strong>Commenter:</strong><%= #user.email %></p>
<p><strong>Comment:</strong><%= comment.body %></p>
<p><%= link_to 'Destroy Comment', [comment.post, comment],method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
Again here I'm having trouble with link to...any suggestions would be great.

You want to make a blog which has users , posts and comments, I see some differences between what you did and what I did it before when I was creating a blog also. I will tell you what I did (by editing the code of the files you posted in your question) then try it if it works with you :)
1- routes.rb make it like this
resources :users
resources :posts do
resources :comments
end
2- user.rb is fine no need to be modified
3- post.rb also is fine
4- comments.rb
belongs_to :post
belongs_to :user
5- posts_controller.rb
def show
#post = Post.find(params[:id])
#comment = Comment.new
end
6- view/posts/show.html.erb ( this view should make you able to see the post and the comments and a box for the new comments, and a link to edit post and a link to the posts index )
<p><strong>Title:</strong><%= #post.title %></p>
<p><strong>Text:</strong><%= #post.text %></p>
<h2>Comments</h2>
<%= render #posts.comments %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<%= link_to 'Edit Post', edit_post_path(#post) %> |
<%= link_to 'Back to Posts', posts_path %>
7- comments_controller.rb ( don't forget to add the destroy method again )
class CommentsController < ApplicationController
before_filter :load_post
def create
#comment = #post.comments.build(params[:comment])
#comment.user_id = current_user.id
if #comment.save
redirect_to #post, notice: "Added comment."
else
render :new
end
end
private
def load_post
#post = Post.find(params[:article_id])
end
end
8- views/comments/_form.html.erb (just try to make it first in a simple way)
<%= form_for([#post,#comment]) do |f| %>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
9- views/comments/_comment.html.erb
<p><strong>Commenter:</strong><%= comment.user.email %></p>
<p><strong>Comment:</strong><%= comment.body %></p>
<p><%= link_to 'Destroy Comment', [comment.post, comment],method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
I hope this work with you as it works with me, try it and let me know how it goes with you, i got my blog work from the before code for revised episode 229.

I got the answer here it is:
posts_controller:
def show
#user = current_user
#post = #user.posts.find(params[:id])
#comment = #post.comments.new
end
show.html.erb:
<p><strong>Title:</strong><%= #post.title %></p>
<p><strong>Text:</strong><%= #post.text %></p>
<% if !#post.comments.empty? %>
<h2>Comments</h2>
<%= render #comment %>
<% end %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<%= link_to 'Edit Post', edit_user_post_path(#user.id,#post) %> |
<%= link_to 'Back to Posts', user_posts_path(#user.id) %>
comments_controller.rb:
def create
#user = current_user
#post = #user.posts.find(params[:post_id])
#comment = #post.comments.create(params[:comment])
redirect_to user_post_path(#user.id,#post)
end
comment's partial
_form.html.erb:
<%= form_for([#user,#post,#comment]) do |f| %>
<p><%= #user.email %></p>
<p><%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p><%= f.submit %></p>
<% end %>

Related

Syntax Error with rails unexpected ')'

Hi there I want to add a destroy action in post#show view I think I have creates the environment but when I place this code with a condition I have a message error.
<% if #user.comment == current_user %>
<% link_to #post_comment_path(post_id: #post.id, id: comment.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<i class="fa fa-trash"></i>
<% end %>
<% end %>
I created a partial in post show#view which names _comments.html.erb
here it is
<p class="text-center">Poster un commentaire</p>
<%= simple_form_for [post, post.comments.new] do |f| %>
<%= f.error_notification %>
<%= f.input :content, label: "Commentaire"%>
<%= f.submit "Envoyer", class: "btn btn-primary" %>
<% end %>
and it render like that <%= render 'comments' %>
and above the partial (in post show#view) I do an iteration like that
<ul class="list-unstyled">
<% #post.comments.each do |comment| %>
<li>
<p><% comment.content %></p>
<% end %>
</li>
</ul>
But nothing appears when I create a new message, I don't userstand why.
I give your more code details
post.rb
has_many :comments, dependent: :destroy
comment.rb
belongs_to :user
belongs_to :post
The route is:
resources :posts do
resources :categories
resources :comments
end
Comments controller is
class CommentsController < ApplicationController
before_action :set_post
def create
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:success] = "You commented the hell out of that post!"
redirect_to :back
else
flash[:alert] = "There is a problem with your comment"
render root_path
end
end
def destroy
#comment = #post.comments.find(params[:id])
#comment.destroy
flash[:success] = "Comment deleted :("
redirect_to root_path
end
private
def set_post
#post = Post.find(params[:post_id])
end
def comment_params
params.require(:comment).permit(:content, :post_id, :user_id)
end
end
Thank you so much for your help.
Your link_to erb code needs an equals sign for it to actually display
<%= link_to post_comment_path(post_id: #post.id, id: comment.id), method: :delete, data: { confirm: "Are you sure?" } do

link_to for nested resources is redirecting incorrectly

I have a simple blog app that has articles. Each article has comments. I'm trying to build nested comments using the closure_tree gem. I've been loosely following this sitepoint tutorial.
I have the following code:
models/article.rb
class Article < ActiveRecord::Base
has_many :comments
end
models/comment.rb
class Comment < ActiveRecord::Base
acts_as_tree order: 'created_at DESC'
end
routes.rb
resources :articles do
resources :comments
get 'comments/new/(:parent_id)', to: 'comments#new', as: :new_comment
end
views/articles/show.html.erb
<h1><%= #article.title %></h1><br>
<h3><%= #article.body %></h3>
Comments:
<% #article.comments.each do |comment| %>
Title: <%= comment.title %>, Body: <%= comment.body %>, User: <%= comment.user_id %>
<%= link_to 'reply', article_new_comment_path(parent_id: comment.id, article_id: #article.id) %>
<% end %>
</ul>
<!-- FORM FOR NEW COMMENT -->
<%= form_for ([#article, #article.comments.build]) do |f| %>
<%= f.hidden_field :parent_id %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
views/comments/new.html.erb
<%= render "form" %>
views/comments/_form/html.erb
<%= form_for ([#comment.article_id, #article]) do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
controllers/comments_controller.rb
[...]
def new
#article = Article.find(params[:article_id])
#comment = Comment.new(parent_id: params[:parent_id])
end
def create
# binding.pry
if params[:comment][:parent_id].to_i > 0
parent = Comment.find_by_id(params[:comment].delete(:parent_id))
#comment = parent.children.build(comment_params)
else
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
[...]
end
When I click the link_to in articles/show.html.erb in order to reply to an existing comment, I hit the new action as expected and pass the comment's parent_id and article_id also as expected into params.
The problem arises when I leave the new action. I expect to hit the form partial and then go into the create action for a comment. Instead I'm somehow hitting the update action for an Article, even though I don't even have one in my ArticlesController. I'm quite a Rails noob and I think I'm messing up in my nested routes. Any help would be much appreciated.
I try to create an action 'subcomment' or 'child' in the controller. Something like this 'post article/:id/comments/:id/child'.
resources :articles do
resources :comments do
post :child
end
end
In action child something like this.
def child
#article = Article.find(params[:article_id]
#comment = #article.comments.find(params[:comment_id])
#child_comment = #comment.children.build(comment_params)
redirect_to article_path(#article)
end
The view is other problem. Iterate over then articles.comments and comments.children and create a form with the url child_article_comment_path(#article, #comment).

Adding Comments to multiple models

Im trying to add comments to my topics model the same way you can add comments to posts on my app. i currently have to partials for comments _comment.html.erb and _form.html.erb
_comment :
<%= content_tag :div, class: 'media', id: "comment-#{comment.id}" do %>
<div class= "media">
<div class= "media-body">
<small>
<%= comment.user.name %> commented <%= time_ago_in_words(comment.created_at) %> ago
<% if user_is_authorized_for_comment?(comment) %>
| <%= link_to "Delete", [comment.post, comment], method: :delete %>
<% end %>
</small>
<p> <%= comment.body %></p>
</div>
</div>
<% end %>
_form :
<h4>Add a comment</h4>
<%= form_for [post, comment] do |f| %>
<div class="form-group">
<%= f.label :body, class: 'sr-only' %>
<%= f.text_field :body, class: 'form-control', placeholder: "Enter a new comment" %>
</div>
<%= f.submit "Submit Comment", class: 'btn btn-default pull-right' %>
<% end %>
my topic show is :
#DISPLAY Topic comments here
<h3> Comments</h3>
<%= render #topic.comments %>
</div>
<% if current_user %>
<%= render 'comments/form', comment: Comment.new, post: #post %>
<% end %>
#------
comment controller :
def create
#post = Post.find(params[:post_id])
comment = #post.comments.new(comment_params)
comment.user = current_user
if comment.save
flash[:notice] = "Comment saved successfully."
redirect_to [#post.topic, #post]
else
flash[:alert] = "Comment failed to save."
redirect_to [#post.topic, #post]
end
end
def destroy
#post = Post.find(params[:post_id])
comment = #post.comments.find(params[:id])
if comment.destroy
flash[:notice] = "Comment was deleted"
redirect_to [#post.topic, #post]
end
end
i have updated the routes for topic comments :
resources :topics do
resources :posts, except: [:index]
resources :comments, only: [:create, :destroy]
end
my question is do i need to create a separate partial to add comments to topics or can i update my _comment partial to work for both post and topic comments . and how can i accomplish this ?
Models
You'll need a polymorphic association on the Comment model:
#app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
#app/models/topic.rb
class Topic < ActiveRecord::Base
has_many :comments, as: :commentable
end
#app/models/post.rb
class Post < ActiveRecord::Base
has_many :comments, as: :commentable
end
Controllers
This will allow you to save the comments for your various models, the controllers / flow coming secondary:
#config/routes.rb
resources :topics, :posts do
resources :comments, only: [:create, :destroy] #-> url.com/topics/:topic_id/comments
end
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
id = params[:post_id] || params[:topic_id]
if params[:post_id]
#parent = Post.find id
elsif params[:topic_id]
#parent = Topic.find id
end
#comment = #parent.comments.find params[:id]
#comment.save
end
def destroy
#parent = params[:post_id] || params[:topic_id]
#comment = #parent.comments.new comment_params
#comment.destroy
end
private
def comment_params
params.require(:comment).permit(:x, :y)
end
end
Because you're passing the data to the comments controller, you'll only need to evaluate which #parent you're working with.
Views
For your views, you need to pass locals to your _form partial:
#app/views/posts/show.html.erb
<%= render "comments/form", locals: {parent: #post} %>
#app/views/comments/_form.html.erb
<%= form_for [parent, parent.comments.new] do |f| %>
I had this road-block as well and here is what I came up with that passed. I must first give #Richard Peck applause for getting my wheels turning, so thank you :).
Models
Did not implement a polymorphic association. Stuck with has_many and belongs_to, nothing more
Partials
_comment.html.erb
Set up the delete partial to accept "parent" as a local
<div class="media">
<div class="media-body">
<small>
<%= comment.user.name %>
commented
<%= time_ago_in_words(comment.created_at) %>
ago
<% if user_is_authorized_for_comment_via_post?(comment) %>
|
<%= link_to "Delete", [parent, comment], method: :delete %>
<% end %>
</small>
<p>
<%= comment.body %>
</p>
</div>
</div>
_form.html.erb
same idea as _comment.html.erb, see above
<h4>Add a comment</h4>
<%= form_for [parent, comment] do |f| %>
<div class="form-group">
<%= f.label :body, class: 'sr-only' %>
<%= f.text_field :body, class: 'form-control', placeholder: "Enter a new comment" %>
</div>
<%= f.submit "Submit Comment", class: 'btn btn-default pull-right' %>
<% end %>
Setting up CommentController
...
def create
# upon clicking on create, determine what param id is passed
if params[:post_id]
# if it is a post id, set instance of post id as #parent
#parent = Post.find(params[:post_id])
elsif params[:topic_id]
# if it is a topic id, set instance of topic id as #parent
#parent = Topic.find(params[:topic_id])
end
# create instance as #comment. Build/create
# comment belonging to #parent (Topic or Post)
#comment = #parent.comments.build(comment_params)
# The comment must be associated to the current user.
# A comment must have a user, and value of user within instance of #comment
# is currently nil. Set user id as current user
#comment.user = current_user
# save comment to database
if #comment.save
# direction of save through if and elsif
# Redirection depends on the comment's parent.
# .is_a? method determines if it is of a certain class. Here, is #parent
# of class Post? Is #parents is the same parent id passed through params?
if #parent.is_a?(Post) # template error with this included: (== params[:post_id])
flash[:notice] = 'Comment saved successfully'
redirect_to [#parent.topic, #parent]
# if not part of the class Post, is it a Topic? If so, save here and
# redirect to the topic after save
elsif #parent.is_a?(Topic)
flash[:notice] = 'Comment saved successfully'
redirect_to #parent
end
end
end
def destroy
comment = Comment.find(params[:id])
# #topic = Topic.find(params[:topic_id])
# topic_comment = #topic.comments.find(params[:id])
# #post = Post.find(params[:post_id])
# post_comment = #post.comments.find(params[:id])
if comment.destroy
flash[:notice] = 'Comment was deleted'
redirect_to :back
else
flash[:alert] = "Comment counld't be deleted. Try again"
redirect_to :back
end
end
...
Passing in Comments from topic/show and post/show
topic/show
Note: notice how locals are passed into the controller from here
...
<div class="row">
<%= render 'comments/form', comment: Comment.new, parent: #topic %>
</div>
<% #topic.comments.each do |comment| %>
<%= render partial: 'comments/comment', locals: { parent: #topic, comment: comment } %>
<% end %>
...
post/show
<% if current_user %>
<% #post.comments.each do |comment| %>
<%= render partial: 'comments/comment', locals: { parent: #post, comment: comment } %>
<% end %>
<% end %>
<% if current_user %>
<%= render 'comments/form', comment: Comment.new, parent: #post %>
<% end %>
Hope this helps.

NoMethodError in CommentsController#create

Im a beginner in rails so i started to follow a tutorial on http://guides.rubyonrails.org/getting_started.html Now im stuck on the 6.4 part when you need to make a comment but i cant figure it out what the problem is. When i want to create a comment im getting this error and oh yeah im on windows
NoMethodError in CommentsController#create
undefined method `title' for # Comment:0x88e4038
this is my comment controller
class CommentsController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
redirect_to article_path(#article)
end
def destroy
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
#comment.destroy
redirect_to article_path(#article)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
This is my show.html.erb
<p>
  <strong>Title:</strong>
  <%= #article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= #article.text %>
</p>
 
<h2>Comments</h2>
<%= render #article.comments %>
 
<h2>Add a comment:</h2>
<%= form_for([#article, #article.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 Article', edit_article_path(#article) %> |
<%= link_to 'Back to Articles', articles_path %>
comment.html.erb
<p>
  <strong>Commenter:</strong>
  <%= comment.commenter %>
</p>
 
<p>
  <strong>Comment:</strong>
  <%= comment.body %>
</p>
 
<p>
  <%= link_to 'Destroy Comment', [comment.article, comment],
               method: :delete,
               data: { confirm: 'Are you sure?' } %>
</p>
and this is the route
Rails.application.routes.draw do
resources :articles do
resources :comments
end
root 'welcome#index'
end
I looked at the tutorial and the comment model has no attribute title. Rails is complaining because you're trying to validate the 'title' attribute in the Comment model:
validates :title, presence: true, length: { minimum: 5 }
Remove this validation.

comments not displaying in ruby on rails blog application

I'm trying to display commenter and body of comments model in blog application. But it is not displaying.
Here is the code of comments controller.
class CommentsController < ApplicationController
http_basic_authenticate_with :name => "dhh", :password => "secret", :only => :destroy
def create
#post=Post.find(params[:post_id])
#comment=#post.comments.create(params[:comments])
redirect_to post_path(#post)
end
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
def check
#comment=Comment.all
end
end
//comment model
class Comment < ActiveRecord::Base
belongs_to :post
attr_accessible :body, :commenter
end
//post model
class Post < ActiveRecord::Base
attr_accessible :content, :name, :title, :tags_attributes
validates :name, :presence=>true
validates :title, :presence=>true,
:length=>{:minimum=>5}
has_many :comments, :dependent=>:destroy
has_many :tags
accepts_nested_attributes_for :tags, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
end
// comment view
<p>
<b>Commenter:</b>
<%= comment.commenter %>
</p>
<p>
<b>Comment:</b>
<%= comment.body %>
</p>
<p>
<%= link_to 'Destroy Comment', [comment.post, comment],
:confirm => 'Are you sure?',
:method => :delete %>
</p>
// Post view
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #post.name %>
</p>
<p>
<b>Title:</b>
<%= #post.title %>
</p>
<p>
<b>Content:</b>
<%= #post.content %>
</p>
<p>
<b>Tags:</b>
<%= join_tags(#post) %>
</p>
<h2>Comments</h2>
<%= render #post.comments %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<br />
<%= link_to 'Edit Post', edit_post_path(#post) %> |
<%= link_to 'Back to Posts', posts_path %> |
Please fix this.
<%= render #post.comments %>
is incorrect. You must render partials, not objects.
I will think that your comment view in views/comments is named show.html.erb. Try something like that:
<%= #post.comments.map do |comment| %>
<%= render 'comments/show', comment: comment %>
<%= end %>
UPD: My mistake: it's correct, description in comments.
Which file is what you call 'comment view'? To be a able to render a collection like this
<%= render #post.comments %>
you need to place a comment template to views/comments/_comment.html.erb
Of course you can place it into another partial, e.g. 'posts/_comment.html.erb` but then you'll have to be more explicit:
<%= render :partial => 'posts/comment', :collection => #post.comments %>
(Mind there is an underscore in the file name, but not in the 'partial path' passed to render)

Resources