简体   繁体   English

Rails模型的to_s方法

[英]Rails model to_s method

In my Rails application there is a relationship defined between Products and Categories. 在我的Rails应用程序中,在“产品”和“类别”之间定义了一种关系。 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: 和我的Category模型:

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? 为什么to_s方法不起作用? How can I solve this? 我该如何解决?

The result of @product.categories is an ActiveRecord::Relation , not an array. @product.categories的结果是ActiveRecord::Relation ,而不是数组。 Therefore the method join is the one implemented inside the relation class, not the Array#join . 因此, join方法是在关系类内部实现的方法,而不是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. 值得一提的是您可以使用to_sentence方法。

<%= @product.categories.pluck(:name).to_sentence unless @product.categories.nil? %>

Moreover, the .nil? 此外, .nil? check is completely useless because @product.categories is a relation and will never be nil. 检查是完全没有用的,因为@product.categories是一个关系,永远不会为零。

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. 要访问属性(如果它是表中的一列),则不应使用@attr_name,因为它们不会存储为实例变量。

Try just to redefine your to_s method like following: 尝试仅重新定义您的to_s方法,如下所示:

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. 这是pry REPL的输出。 It's not quite a Rails model but it points out the issue. 它不是一个Rails模型,但指出了这个问题。

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 . 不是to_s It's to_str , apparently, that is called. 显然是to_str

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM