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
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
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).
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.
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.
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)