1

i'mtrying a simple feature where a user can comment on inquest post , but comment .user.username is not working ,it's rendering comment.user but does not support user attributes

create_table "comments", force: :cascade do |t|
t.string "content"
t.integer "inquest_id"
t.integer "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["inquest_id"], name: "index_comments_on_inquest_id"
t.index ["user_id"], name: "index_comments_on_user_id"
end

comment_model

class Comment < ApplicationRecord
belongs_to :inquest 
belongs_to :user
end

user_model is simple with has many comments association

comments create method of controller

  def create

@comment = Comment.new(comment_params)

pp comment_params
@inquest = Inquest.find(params[:inquest_id])
@comment = Comment.new(comment_params)
@comment.inquest = @inquest
@comment.user = current_user
respond_to do |format|
  if @comment.save
    format.js do
      @inquest = Inquest.find(params[:inquest_id])

    end
  else
    format.html { render :new, status: :unprocessable_entity }
    format.json { render json: @comment.errors, status: :unprocessable_entity }
  end
end
end

I'm rendering comments in inquest's show.html.erb

Showing /Users/zunairaihsan/Desktop/fyp_ed_bolt/app/views/inquests/show.html.erb 
   where line #123 raised:

 undefined method `user_name' for nil:NilClass

I've tried most of the ways possible , but it's not working.please let me know where I'm wrong

  • To find `nil` values in your views use inspect `comment.user.inspect`, otherwise you're probably missing the broken comment and only seeing the comments that have a user. – Alex Apr 16 '22 at 19:26

1 Answers1

1

I assume, in inquests/show.html.erb you're displaying multiple comments, something like

<%= @inquest.comments.each do |comment| %>
  <%= comment.user.user_name %>
  <%= comment.content %>
<% end %>

Many comments will render without issue. Comment model and database doesn't allow user_id to be nil.

But looks like one comment's user_id doesn't have a corresponding id in users table. When you try to figure out what's going on and remove user_name

<%= @inquest.comments.each do |comment| %>
  <%= comment.user %>
  <%= comment.content %>
<% end %>

Sneaky broken comment probably doesn't show you anything, comment.user is nil, and because you have no validation on comment.content it could also be nil.

First, get rid of comments without user to verify this is the issue:

# this is fast enough for a few thousand comments
>> Comment.find_each { |comment| comment.destroy unless comment.user }

After this inquests/show.html.erb should be working.

To make sure this doesn't happen again:

class User
  # this will delete all `user.comments` when you destroy `user`
  has_many :comments, dependent: :destroy

  # ...
end

To really make sure this doesn't happen again:

class CreateComment < ActiveRecord::Migration[7.0]
  def change
    create_table :comments do |t|
      t.references :user, null: false, foreign_key: true
      
      # ...
    end
  end
end

With foreign_key constraint, your database will not let you destroy a user if they have comments. This works in tandem with dependent: :destroy. If you delete a user and rails automatically destroys all user.comments, then database will not complain.

Probably do the same for inquest as well if it's not optional.

Also comments without content are not really comments:

class Comment < ApplicationRecord
  belongs_to :inquest 
  belongs_to :user

  validates :content, presence: true
end
Alex
  • 16,409
  • 6
  • 40
  • 56
  • 1
    thanks much Alex , this cleared things for me , I was rendering user_name and content without making sure that comment persited or not , and after applying conditions it worked for me. – Zunaira Ihsan Apr 16 '22 at 21:17