how to display comments for posts in rails (by iteration ) - ruby-on-rails

I managed to link comments to their posts in rails but the remaining thing is displaying them and here is my view(simplified) :
the thing is that iam iterating through post.all and each post has_many :comments and each comment has comment.description comment.image so how can I get to show the comment for each of the iterated posts is it by another iteration ?
_profile.html.erb :
#posts.each do |x|
<div class="eachpost-wrapper">
<%= x.text %>
<%= x.picture %>
<div class="comments-for-each-post">
<<<<<<<<< the post comments are supposed to be here <<<<<<
</div>
</div>
<% end %>
accounts controller :
def profile
#posts = User.find(params[:id]).posts
#comment = Comment.new
end
comments controller :
def new
#comment = Comment.new
end
def create
#post = Post.find(params[:id])
#comment = #post.comments.new
if #comment.save
redirect_to "success/success"
else
redirect_to 'error/error404'
end

Yes, it is by another iteration. Something along the lines of:
<div class="posts-wrapper">
<% #posts.each do |post| %>
<div class="post-wrapper">
<%= post.text %>
<%= post.picture %>
<div class="comments-wrapper">
<% post.comments.each do |comment| %>
<div class="comment-wrapper">
# do stuff with comment here...
</div>
<% end %>
</div>
<div class="new-comment-wrapper">
# put a new comment form in here...
</div>
</div>
<% end %>
</div>
Keeping in mind what MrYoshiji said about eager loading...

Related

Comments not displaying from rendered form

I am new to Ruby and I am trying to display comments on my show page but when I create a comment it does not display. I have rendered a partial on my show page in order to display the comments but they do not appear.
The strange thing is that the create action works but it takes me to this page: http://localhost:3000/hairstyles/2/comments which has nothing on it (in my app this page is under views>comments>create.html.erb) instead i'd like it to go to the view page for the hairstyle and display the comment..........
If anyone can help and see if there are any errors in my code I'd be grateful. Thanks in advance.
Comments Controller:
class CommentsController < ApplicationController
def new
#hairstyle = Hairstyle.find(params[:hairstyle_id])
#comment = Comment.new
end
def create
#comment = Comment.new(comment_params)
#hairstyle = Hairstyle.find(params[:hairstyle_id])
#comment.save
end
def destroy
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
Hairstyle view page where I want to display the comments:
<div class="container">
<div>
<%= cl_image_tag #hairstyle.photo, width: 300, height: 200, crop: :fill %>
<h1><%= #hairstyle.name %></h1>
<p><%= #hairstyle.description%></p>
<p><%= #hairstyle.category%></p>
<p><%= #hairstyle.video_url %></p>
</div>
</div>
<div>
<%= link_to 'Back', hairstyles_path %>
</div>
<h6>Comments for: <%= #hairstyle.name %> <small><%= %></small></h6>
<h2>
<%= pluralize #hairstyle.comments.size, "comment" %>
</h2>
<div id="comments">
<% if #hairstyle.comments.blank? %>
Be the first to leave a comment for <%= #hairstyle.name %>
<% else %>
<% #hairstyle.comments.each do |comment| %>
<%= render 'comments/show', comment: comment %>
<% end %>
<% end %>
</div>
<%= render 'comments/form', comment: #comment %>
Comments form i am rendering which does work and is displayed:
views>comments>_form.html.erb
<div class="flex-box">
<%= simple_form_for([ #hairstyle, comment ]) do |form| %>
<%= form.input :content, as: :text %>
<%= form.button :submit %>
<% end %>
</div>
Comments content that I am rendering that does not display once I have added a comment to my hairstyle on the show page:
views>comments>_show.html.erb
<p><%= comment.content %></p>
The default behavior of rails controllers is it will redirect to the index page after the create method. that's why you are redirected to that path.
you can simply use redirec_to in your create method in your comment controller like below
def create
#comment = Comment.new(comment_params)
#hairstyle = Hairstyle.find(params[:hairstyle_id])
#comment.save
redirect_to hairstyle_path(#comment.hairstyle)
end
You never link your comment to your hairstyle, your hairstyle_id from your comment is nil this is why #hairstyle.comments returns an empty array
def create
#hairstyle = Hairstyle.find(params[:hairstyle_id])
#comment = #hairstyle.comments.build(comment_params)
# equivalent to:
# comment = Comment.new(comment_params)
# comment.hairstyle = #hairstyle
if comment.save
redirect_to hairstyle_path(#hairstyle)
else
# handle errors
end
end

Ruby on Rails - First argument in form cannot contain nil or be empty in Posts#show

I've been making a blog system in Rails while learning the basics of Rails. However, I have encountered an error: "First argument in form cannot contain nil or be empty" in Posts' "show" view, as I want the comment form to be below the contents of the post. I have tried every solution to the problem including browsing other people's responses on Stack Overflow, however so far to no avail.
CommentsController.rb
class CommentsController < ApplicationController
def index
#comments = Comment.all
end
def new
#comment = Comment.new
end
def create
#post = Post.find(params[:comment[:id])
#comments = #post.comments.create(params[:comment])
if #comments.save
flash[:success] = "Your comment has been successfully created."
redirect_to #post
else
flash[:danger] = "Oops! Something went wrong!"
redirect_to #post
end
end
def edit
#comment = Comment.find(params[:id])
end
def update
#comment = Comment.find(params[:id])
if #comment.update_attributes
flash[:success] = "Your comment has been successfully updated."
redirect_to user_path
else
redirect_to user_path
end
end
def destroy
#comment = Comment.find(params[:id])
if #comment.destroy
flash[:success] = "Your comment has been successfully deleted."
redirect_to post_path
else
flash[:danger] = "Oops! Something went wrong. Try again."
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
show.html.erb (posts)
<div class="show_post">
<div class="container">
<div class="col-lg-9 col-md-9 col-sm-12 col-xs-12 col-lg-offset-3 col-md-offset-3">
<h2 class="heading">
<%= #post.title %>
</h2>
<%= raw(#post.content) %>
</div>
<div class="col-lg-9 col-md-9 col-sm-12 col-xs-12 col-lg-offset-3 col-md-offset-3">
<h4>
Liked this post? Add a comment below!
</h4>
<%= form_for(#comment) do |c| %> # Line that raises the error
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2>
<%= "#{pluralize(#comment.errors.count, "error")} errors were detected in your form:" %>
</h2>
<ul>
<% #comment.errors.full_messages.each do |message| %>
<li>
<%= message %>
</li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= c.label :content, "Your comment goes here: " %>
<%= c.cktext_area :content, rows: 10, class: "form-control" %>
</div>
<div class="form-group">
<%= c.submit "Add Comment", class: "btn btn-primary" %>
</div>
<% end %>
</div>
<div class="col-lg-9 col-md-9 col-sm-12 col-xs-12 col-lg-offset-3 col-md-offset-3">
<h3>
Comments:
</h3>
<% if #comments && #comments.any? %>
<% #comments.each do |comment| %>
<%= raw(comment.content) %>
<% end %>
<% end %>
</div>
</div>
routes.rb
Rails.application.routes.draw do
root 'pages#home'
get 'help' => 'pages#help'
get 'contact' => 'pages#contact'
get '/index' => 'users#index'
get '/signup' => 'users#new'
post '/users' => 'users#create'
get '/show' => 'users#show'
get '/login' => 'sessions#new'
post '/login' =>'sessions#create'
get '/logout' => 'sessions#destroy'
get '/new_post' => 'posts#new'
post '/new_post' => 'posts#create'
get '/show_post' => 'posts#show'
get '/delete_post' => 'posts#destroy'
resources :users
resources :posts
resources :comments
I'm still a n00b in Rails, so I need help with solving this issue.
Thanks in advance.
Variable #comment in your show view is nil. Set it in the controller action to new comment:
def show
#...
#comment = Comment.new
end
You don't seem to have a show method in your CommentsController class. The show view is called from the show method. The error arises because you haven't initialized the #comment instance variable anywhere. So that's why it's complaining saying #comment is nil.
Simply put this method into your controller
def show
#comment = Comment.new
end
If your comment form appears in the User Show view, you have to specify the #comment instance variable in the the show action of the User Controller or else Rails doesn't know what #comment means.
UserController.rb
def show
#comment = Comment.new
end
The #post variable in your create action will cause an error because there is no comment id in the user show action (user/1/show). You will have to find a way to pass the comments id to your comment create action.

how to hide database information on view?

when I attempt to run my code, I got the error above.
As you can see on the following image, the page posts/index leaves appear some information before the footer of the page :
I don't understand where it may come, because it's the only page where it appeared.
Here's my view :
<%= #post.each do |post| %>
<h1 class="Blog_post_title"><%= link_to post.title, post %></h1>
<p class="date"><%= post.created_at.strftime("%B, %d, %Y") %></p>
<p><%= image_tag post.landing_image.url , class: "landing_image_blog" %></p>
<p><%= post.body %></p>
<%= link_to post do %>
<div class="button12">Continuer la lecture</div>
<% end %>
<div class="border_grey_blog"></div>
<% end %>
</div>
<%= render "footer" %>
my posts_controller.rb:
class PostsController < ApplicationController
def index
#post = Post.all.order('created_at DESC')
end
def new
#post = Post.new
end
def show
#post = Post.find(params[:id])
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title,:title2,:title3,:title4,:title5,:title6,:title7,:title8,:title9, :body, :image,:image1,:image2,:image3,:image4,:image5,:image6,:image7,:image8, :landing_image, :some_text1, :some_text2, :some_text3, :some_text4, :some_text5, :some_text6, :some_text7, :some_text8, :some_text9, :some_text0))
redirect_to #post
else
render 'edit'
end
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to "/posts"
end
private
def post_params
params.require(:post).permit(:title, :body, :image,:image1,:image2,:image3,:image4,:image5,:image6,:image7,:image8, :landing_image, :some_text1, :some_text2, :some_text3, :some_text4, :some_text5, :some_text6, :some_text7, :some_text8, :some_text9, :some_text0, :title2,:title3,:title4,:title5,:title6,:title7,:title8,:title9)
end
end
Any idea ?
Your mistake is in the very first line of the view:
<%= #post.each do |post| %>
should be
<% #post.each do |post| %>
since <%= opens an expression tag that will display its content.
It looks like your outputting the result of #posts.each. Notice how you did this in your view:
<%= #post.each do |post| %>
# other code
<% end %>
This will actually output all the data in the array as a ruby object. If you want to change this to not output everything, you need to change it to
<% #post.each do |post| %>
# other code
<% end %>
This will now not return the #post.each in the html.

Rails 4 view rendering extra object in view?

I have comments as a subresource of articles, as below:
resources :articles do
resources :comments
end
I want each Article's show page to display all of its corresponding comments, as well as have a form where a user (if signed in) can create a new comment that corresponds with the article.
Here's the show action for ArticlesController:
def show
#comment = #article.comments.build
if user_signed_in?
#comment.user_id = current_user.id
end
respond_with(#article)
end
Here's relevant code from the CommentsController:
before_action :set_article
...
def create
#comment = #article.comments.create(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:notice] = "Comment successfully created!"
end
redirect_to #article
end
...
private
def set_article
#article = Article.find(params[:article_id])
end
end
And here's the Article show view:
<b>Post comments:</b><br />
<table>
<thead>
<tr>
<th>User email</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
<% #article.comments.each do |comment| %>
<tr>
<td><%= comment.user.email %></td>
<td><%= comment.body %></td>
</tr>
<% end %>
</tbody>
</table>
<br />
<%= form_for ([#article, #comment]) do |f| %>
<div class="field">
<%= f.text_area :body, placeholder: "Compose new comment..." %>
</div>
<%= f.submit "Post" %>
<% end %>
Here's the two situations I need to fix:
When no user is signed in, the view fails to render because comment.user returns nil
When a user is signed in, a phantom comment for each article appears, because the show action in the ArticlesController is building a new (empty) comment with #comment = #article.comments.build
What is the best way to simultaneously solve both of these problems?
If you don't want to do that in the view, you can do this sort of thing in the controller.
def show
#comment = Comment.new(:article => #article)
respond_with(#article)
end
This won't add the comment to the article.comments array and won't try to render a blank comment.
Do you need to set the user_id on the comment in the form on the show action? If not, you can do this in create
def create
#comment = Comment.new(comment_params)
#comment.article = #article
#comment.user = current_user
if #comment.save
flash[:notice] = "Comment successfully created!"
redirect_to #article
else
render :show
end
end
The benefit to this - you can now handle errors in the form (like if they submit a blank comment, or minimum characters). Even if you handle it in the view with javascript/disabled buttons, it's nice to have the server also support validations and errors.
Just kidding, got it.
Put the build call into the form rather than the ArticleController:
<%= form_for ([#article, #article.comments.build]) do |f| %>
<div class="field">
<%= f.text_area :body, placeholder: "Compose new comment..." %>
</div>
<%= f.submit "Post" %>
<% end %>
and delete everything out of the show action:
def show
respond_with(#article)
end

How to create a questions list where answer_form will be in every question_partial?

I want to create a web page where i can see my item with list of questions.
"items/1/questions"
in routes.rb i have
resources :items do
resources :questions
end
questions/index.html.erb
<div class="panel panel-default">
<div class="panel-heading">
<td><%= #item.title %></td>
</div>
<div class="panel-body">
<p><%= #item.description %></p>
<p><%= #item.price %></p>
</div>
</div>
<div class="panel-body"><%= render 'questions/form' %></div>
<div class="panel-body">
<% if #item.questions.any? %>
<%= render partial: 'questions/question', collection: #item.questions %> </div>
<% end %>
</div>
question/_question.html.erb
<p><%= question.body %></p>
Now i want to create an answer-option for admin, looks like the answer field in every question_partial.
So i create a model Answer, belongs_to :question (in Question model has_one :answer), question_id:integer, body:string.
In answers_controller.rb
...
def new
#answer = Answer.new(answer_params)
end
def create
#question = Question.find(params[:question_id])
#answer = #question.build_answer(answer_params)
if #current_user == #admin
#answer.save
flash[:success] = "Your answer has been sent!"
redirect_to item_questions_path(#item)
else
flash[:errors] = "Your answer hasn't been sent!"
redirect_to item_question_path(#item)
end
end
def show
#answer = Answer.find(params[:id])
end
and trying to create a form_for #question.answer
question/_question.html.erb
<p><%= question.body %></p>
<% if #current_user = #admin %>
<%= form_for Answer.new do |f| %>
<p>
<%= f.text_field :body" %>
</p>
<p>
<%= f.submit "answer"%>
</p>
<% end %>
<% end %>
and get the error "undefined method `answers_path'"
I want to build item_page with questions-list where every question_partial should have: answer or answer_form (all on one page, 'items/:id/questions')
i think i have a problem in router (maybe in answers_controller too),
but have no idea how could it organize.
did you have an idea?)
ty
You are getting the error undefined method 'answers_path' because you don't have a route to the answer create action (or any answer actions). Add resources :answers to your route file underneath your other routes.
You need to define the route for the answer, following your approach of nested resources this could look like:
routes.rb
resources :items do
resources :questions do
resource :answer
end
end
The url will now look like /items/:item_id/questions/:question_id/answer which means there is no answer id in the url since it's a singular resource i.e a question can only have one answer. You also have to adapt your controller to fetch the question first and then access the answer like #question.answer
answers_controller.rb
def new
# first find the question, then build an answer for it
#question = Question.find(params[:question_id])
#answer = #question.build_answer
end
def show
#question = Question.find(params[:question_id])
# NOTE: #answer can be nil here if no answer has been created
#answer = #question.answer
end
In your view you got another typo, you used the assignment operator = for comparison. I've also changed the form_for helper to build the correct url.
question/_question.html.erb
<p><%= question.body %></p>
<% if #current_user == #admin %>
<%= form_for [question.item, question, question.answer.present? ? question.answer : question.build_answer] do |f| %>
<p>
<%= f.text_field :body" %>
</p>
<p>
<%= f.submit "answer"%>
</p>
<% end %>
<% end %>

Resources