In my Rails application there is a relationship defined between Products and Categories. Each product can have different categories.
I am displaying the product's category this way:
<p>
<strong>Categories:</strong>
<%= @product.categories.join(", ") unless @product.categories.nil? %>
</p>
And my Category
model:
class Category < ActiveRecord::Base
def to_s
@name
end
end
However, in the show page, the categories are displayed like this:
Categories: #<Category:0x007f2bf515b148>, #<Category:0x007f2bf515aef0>, #<Category:0x007f2bf515ac98>
Why is the to_s
method not working? How can I solve this?
The result of @product.categories
is an ActiveRecord::Relation
, not an array. Therefore the method join
is the one implemented inside the relation class, not the Array#join
.
You should implicitly cast the list to array
<%= @product.categories.to_a.join(", ") unless @product.categories.nil? %>
or you should pay a little bit more attention of what you really need, avoid loading the entire objects and obtain a more efficient result.
<%= @product.categories.pluck(:name).join(", ") unless @product.categories.nil? %>
It is worth mentioning you can use the to_sentence
method.
<%= @product.categories.pluck(:name).to_sentence unless @product.categories.nil? %>
Moreover, the .nil?
check is completely useless because @product.categories
is a relation and will never be nil.
And if you really want to write better code, you avoid implementing your logic in the view and you rely on helpers and models.
class Product
def category_names
categories.pluck(:name)
end
end
module ProductsHelper
def product_categories_list(product)
product.category_names.to_sentence
end
end
<%= product_categories_list(@product) %>
try do define method like:
class Category < ActiveRecord::Base
def to_s
self.name
end
end
To access your attribute, if it is a column in your table, you should not use the @attr_name, as they are not stored as instance variables.
Try just to redefine your to_s
method like following:
class Category < ActiveRecord::Base
def to_s
name
end
end
It is really interesting the way this behaves:
class Role < ActiveRecord::Base
def to_s
nil
end
end
Then
"#{Role.first}"
=> "#<Role:0x00000007a39f88>"
But:
Role.first.to_s
=> nil
I have conducted an experiment to locate the problem and I suggest you look at results.
This is output of a pry
REPL. It's not quite a Rails model but it points out the issue.
What I did: I defined a new class and instructed it to output the names af any non-existent methods that are called on it. This is a handy trick to determine implicit calls on your classes.
[1] pry(main)> class Hi
[1] pry(main)* def method_missing(sym)
[1] pry(main)* puts sym
[1] pry(main)* end
[1] pry(main)* end
=> :method_missing
[2] pry(main)> a = [Hi.new, Hi.new]
=> [#<Hi:0x0000000405b028>, #<Hi:0x0000000405afd8>]
[3] pry(main)> a.join
to_str
to_str
to_ary
to_str
to_ary
=> "#<Hi:0x0000000405b028>#<Hi:0x0000000405afd8>"
It's not to_s
. It's to_str
, apparently, that is called.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.