Antonio Antonio - 1 month ago 11
Ruby Question

Rails 5: @post.comments is empty, yet <% if @post.comments %> doesn't execute the else block and instead acts as if true

Rails 5 app

I'm having an issue where inside a view I have a simple set of ERB tags:

<% if @post.comments %>
<p>Comments here</p>
<% else %>
<p>No comments yet</p>
<% end %>


Obviously, if comments don't exist within
@post
, to execute the bottom block of code. There are no comments in the database, either attached to this
@post
or any other
post
. However, it's executing the top block and I'm seeing
<p>Comments here</p>
rendered on the page.

If I
byebug
inside the view,
@post.commments.any?
returns
false
. and
@post.comments
returns:

Comment Load (1.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = $1 AND "comments"."commentable_type" = $2 [["commentable_id", 4], ["commentable_type", "Post"]]
#<ActiveRecord::Associations::CollectionProxy []>


Does this not count as false? Shouldn't
<% if @post.comments %>
go to the
else
block?

Schema:

create_table "comments", force: :cascade do |t|
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "commentable_id"
t.string "commentable_type"
end

create_table "forums", force: :cascade do |t|
t.string "name"
t.text "description"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_forums_on_user_id", using: :btree
end

create_table "posts", force: :cascade do |t|
t.string "title"
t.text "description"
t.integer "user_id"
t.integer "forum_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["forum_id"], name: "index_posts_on_forum_id", using: :btree
t.index ["user_id"], name: "index_posts_on_user_id", using: :btree
end

create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
...
# Devise stuff removed for brevity.
...
end

add_foreign_key "posts", "forums"
add_foreign_key "posts", "users"


My models:

#User model.
has_many :forums
has_many :posts

#Forum model.
belongs_to :user
has_many :posts

#Post model.
belongs_to :user
belongs_to :forum

#Comment model.
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable

Answer

Because in Ruby just false and nil are falsey values. I mean, those values that are false in a boolean context. In your code probably @post.comments is [] and [] is true in Ruby.