Show errors for comments if validation fails

2019-09-06 09:25发布

问题:

I'm having a form where a loggedin user can add comments to a post. This is my code in my files, so far:

# views/posts/show.html.haml
%h3 This post has #{ pluralize(@post.comments.count, "comment") }
= render @post.comments # views/comments/_comment.html.haml
= render "comments/form" 

# views/comments/_comment.html.haml - list all comments of the post
.media
  .media-body
    %h4.media-heading
      = comment.user.name
      %small added #{time_ago_in_words comment.created_at} ago
    %p= comment.body
%hr

# views/comments/_form.html.haml
- if user_signed_in?
  = errors_for @comment if @comment # errors_for is just a custom helper I've created to loop through all validation errors

  = form_for([@post, Comment.new]) do |f|
    .form-group
      = f.label :body, "Leave a comment"
      = f.text_area :body, class: "form-control", rows: "6"
    .form-group
      = f.submit "Add", class: "btn btn-primary"

# controllers/comments_controller.rb
def create
    @post = Post.find(params[:post_id])

    @comment = @post.comments.create(params[:comment].permit(:body).merge(:user => current_user))

    if @comment.errors.any?
      render "posts/show"
    else
      redirect_to post_path(@post)
    end

    # have also tried this way too
    # @comment = @post.comments.build(params[:comment].permit(:body))
    # @comment.user = current_user
    # if @comment.save
    #  redirect_to post_path(@post)
    # else
    #  render "posts/show"
    # end
end

When I click the submit button to add a comment with the form being empty (the comment body is required) I get this odd error (better errors gem)

NoMethodError at /posts/1/comments

undefined method `>' for nil:NilClass

and highlights this line of code %small added #{time_ago_in_words comment.created_at} ago in _comment.html.haml. In addition the postID and userID is assigned to the @comment as expected, and the comment.body and created_at and updated_at are nill, as expected.

I have temporarily removed all the ruby embeded code from this file and everything works ok - except from the fact that I don't get the list of the comments - the validations works as expected and I can see the errors on my screen.

How can I fix this?

EDIT

Works fine, however I 'm struggling with one more thing. If the post has already some old comments, I'm getting a warning for N+1 Queries running.

N+1 Query detected
  Comment => [:user]
  Add to your finder: :includes => [:user]
N+1 Query method call stack
  /app/views/comments/_comment.html.haml:5:in `_app_views_comments__comment_html_haml__3499194119219243109_33739760'
  /app/views/posts/show.html.haml:23:in `_app_views_posts_show_html_haml__2205508389884571191_36379560'
  /app/controllers/comments_controller.rb:10:in `create'

/app/views/comments/_comment.html.haml:5:in `_app_views_comments__comment_html_haml__3499194119219243109_33739760'
/app/views/posts/show.html.haml:23:in `_app_views_posts_show_html_haml__2205508389884571191_36379560'
/app/controllers/comments_controller.rb:10:in `create'

I know that this is off topic, but any ideas how to fix this? Where exactly do I need to use .includes(:user) ??

回答1:

As you have already stated "created_at ... is nil". Even though your line of code is commented out it will still be evaluated by erb, resulting in time_ago_in_words throwing the nil exception. It would be better to use a conditional statement such as:

# views/comments/_comment.html.haml - list all comments of the post
.media
  .media-body
    %h4.media-heading
      = comment.user.name
      - if comment.created_at.present?
        %small added {time_ago_in_words comment.created_at} ago
      - else
        % small comment not yet been created
    %p= comment.body
%hr