Reputation: 156
I want show the user email as author of comment, but I see this error "undefined method `email' for nil:NilClass" comment.rb
class Comment < ActiveRecord::Base
belongs_to :hotel
belongs_to :user
end
user.rb
class User < ActiveRecord::Base
has_many :hotels
has_many :comments
end
hotel.rb
class Hotel < ActiveRecord::Base
belongs_to :user
belongs_to :address
has_many :comments
mount_uploader :avatar, AvatarUploader
accepts_nested_attributes_for :address
end
comments_controller.rb
def create
@hotel = Hotel.find(params[:hotel_id])
@comment = @hotel.comments.new(comment_params)
@comment.user_id = current_user.id
@comment.save
redirect_to @hotel
end
private
def comment_params
params.require(:comment).permit(:user_id, :body, :hotel_id)
end
_comments.html.haml
= div_for comment do
%p
%strong
Posted #{time_ago_in_words(comment.created_at)} ago
%br/
= h comment.user.email
%br
= comment.body
Upvotes: 1
Views: 526
Reputation: 76784
Method
The error that you're calling a method which doesn't exist.
The problem is you're calling a method on an associated object which doesn't exist. You probably don't have any user
associated to the comment
- thus preventing you from being able to call the email
method.
Firstly, you need to make sure you have the correct association. Here's how to do that:
$ rails c
$ comment = Comment.find([id])
$ comment.update(user_id: [your_user_id])
$ exit
This will allow you to associate the comment to a particular user, giving you the ability to call the associated method.
--
Controller
When you save your comment
in your controller, you need to assign your user
to it. We do this using the strong_params
functionality, as its the DRYest way we've found:
#app/controllers/comments_controller.rb
Class CommentsController < ApplicationController
def create
@comment = Comment.new(comment_params)
end
private
def comment_params
params.require(:comment).permit(:your, :comment: attributes).merge(user_id: current_user.id)
end
end
This will allow you to associate the user at save time, giving you the ability to call the methods you need next time you call the record!
Delegate
You'll also benefit from using the delegate
method like this:
#app/models/comment.rb
Class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :hotel
delegate :email, to: :user, prefix: true #-> allows you to call `@comment.user_email`
end
This will solve the law of Demeter issue (where you should aim to have one "point" in your calls")
Upvotes: 3