1
votes

I am a new student to Ruby on Rails and am currently working on the Deletion HTTP request for my project, a Reddit clone. So far I have implemented Destroy functionality on Topics and Posts successfully. Now that I am working on the deletion of Comments I have hit an error that I am not sure how to deal with.

Here was the instruction.

Finally, we also have to modify the comment-listing view -- the app/views/comments/_comment.html.erb partial called in posts#show. Update the partial to look this:

<div class="media">
  <div class="media-left">
    <%= image_tag(comment.user.avatar.small.url, class: "media-object") if comment.user.avatar? %>
  </div>
  <div class="media-body">
    <small>
      <%= comment.user.name %> commented <%= time_ago_in_words(comment.created_at) %> ago
      <% if policy(comment).destroy? %>
        | <%= link_to "Delete", [@topic, @post, comment], method: :delete %>
      <% end %>
    </small>
    <p><%= comment.body %></p>
  </div>
</div>

My _comment.html.erb before the change:

<% @comments.each do |comment| %>

  <p><%= comment.body %></p>
  <p><i><%= comment.user.name %></i></p>

<% end %>

After modifying the code as instructed I receive this error:

NoMethodError at /topics/4/posts/11 undefined method `avatar?' for nil:NilClass

With this line highlighted:

<%= image_tag(comment.user.avatar.small.url, class: "media-object") if comment.user.avatar? %>

Here is my views/post/show.html.erb:

<h1><%= markdown_to_html @post.title %></h1>

<div class="row">
  <div class="col-md-8">
    <small>
      <%= image_tag(@post.user.avatar.tiny.url) if @post.user.avatar? %>
      submitted <%= time_ago_in_words(@post.created_at) %> ago by
      <%= @post.user.name %>
    </small>
    <p><%= markdown_to_html @post.body %></p>
    <p><%= image_tag(@post.image.post.url) if @post.image? %>

    <h1>Comments</h1>
    <!-- render the comments loop -->
    <%= render partial: 'comments/comment', locals: { topic: @topic, post: @post, comment: @comment } %>

    <!-- render the comments form if user is signed in -->
    <% if policy(@comment).create? %>
      <%= render partial: 'comments/form', locals: { topic: @topic, post: @post, comment: @comment } %>
    <% end %>

  </div>
  <div class="col-md-4">
    <% if policy(@post).edit? %>
      <%= link_to "Edit", edit_topic_post_path(@topic, @post), class: 'btn btn-success' %>
    <% end %>
    <% if policy(@post).destroy? %>
      <%= link_to "Delete Post", [@topic, @post], method: :delete, class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete this post?' } %>
    <% end %>
  </div>
</div>

comments controller

class CommentsController < ApplicationController
  def create
    # find topic by id
    @topic = Topic.find(params[:topic_id])
    # find post id through topic
    @post = @topic.posts.find(params[:post_id])
    # comments on post
    @comments = @post.comments

    @comment = current_user.comments.build(params.require(:comment).permit(:body, :post_id, :avatar))
    @comment.post = @post


    authorize @comment
    if @comment.save
      flash[:notice] = "Comment was created."
      redirect_to [@topic, @post]
    else
      flash[:error] = "Error saving the comment. Please try again."
      # must render the the page calling the form!!
      render 'posts/show'
    end
  end

  def new

  end

  def destroy
    @topic = Topic.find(params[:topic_id])
    @post = Post.posts.find(params[:post_id])
    @comment = @post.comments.find(params[:id])

    authorize @comment
    if @comment.destroy
      flash[:notice] = "Comment was removed."
      redirect_to [@topic, @post]
    else
      flash[:error] = "Comment couldn't be deleted. Try again."
      redirect_to [@topic, @post]
    end
  end
end

user model

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :confirmable
  has_many :posts
  has_many :comments

  # CarrierWave method for attribute functionality
  mount_uploader :avatar, AvatarUploader

  # These methods check the role of a user in the database
  def admin?
    role == 'admin'
  end

  def moderator?
    role == 'moderator'
  end
end

I have attempted to change my comment.user.avatar.small.url to @comment.user.avatar.small.url based off how the rest of my images were handled in the project. The error still persists.

Best regards.

1
You have a comment that is not connected to a user in your database and therefor comment.user is nil. And nil doesn't have a method called avatar?.Mischa

1 Answers

3
votes

This is error means that comment.user is nil. If you want to fix it you should investigate why this happens.

If this is the correct case (for example this is an anonymous user) then you can handle it use something like:

... if comment.user.try(:avatar?)