Reputation:
My Article
model has_many
instances of my Comment
model, which has a text
attribute.
However, in my view, when I call through iteration article.comments.last.text
I get undefined method
error.
I must say that when I call it through the console, it does return the text attribute.
The log's only relevant response to this error is:
ActionView::Template::Error (undefined method `text' for nil:NilClass):
View code:
- @articles.each do |article|
.article
%comment= article.comments.last.text
Upvotes: 1
Views: 54
Reputation: 1549
First thing to mention is that you have N+1 problem here. You are querying your database on each article to get all it's comments. It's may slowdown your system.
I suggest the next approach for this solution.
Define new relation in Article
class Article < ActiveRecord::Base
has_one :last_comment, -> { where(created_at: :desc) }, class_name: 'Article'
end
Load this relation in your controller
def your_action
# you can continue querying as I show you with 'where' and 'your_scope', the 'includes' is a must to
@articles = Article.includes(:last_comment).where(...).your_scope
...
end
Then in your view just use the next code
- @articles.each do |article|
.article
- if article.last_comment.present?
%comment= article.last_comment.text
Upvotes: 1
Reputation: 76774
To add to the accepted answer, the problem is defined with the error:
--
undefined method `text' for nil:NilClass
It means you're calling text
on a class
/ variable
/ data-set
which isn't populated (nil
).
As mentioned, the way to do this is to evaluate whether an article has any .comments
. Whilst .try(:x)
is the best way to do it, the more verbose way is to use conditional logic:
%comment= article.comments.last.text if article.comments.any?
--
it does return the text attribute
Maybe the comment
exists, but it isn't associated to article
.
Calling article.comments
only calls the comments
associated to article
(through their respective foreign keys). If the comment
is not associated to article
, it won't appear in the collection.
Thus, if you're checking whether text
exists for a comment, you also need to make sure the comment is associated with article
. A simple way to do this is through the Rails Console:
$ rails c
$ article = Article.first
$ comment = Comment.first
$ article.comments << comment
Upvotes: 1
Reputation: 10053
You should do some defensive coding when trying something like this. article.comments.last.text
. There will always be a possibility when article.comments
is blank. It returns an empty array [].So when you execute something like .last.text
. It will break the code throwing error.
You can check something like article.comments.present?
and then access the last comment.
Upvotes: 1
Reputation: 797
Update your view code to following. I hope it works for you.
- @articles.each do |article|
.article
%comment= article.comments.last.try(:text)
Upvotes: 3