Ruby on rails 我可以对rails模型中的计算值使用实例方法吗?
我有一个模型,它的数据中有一个时间长度(分和秒列)。我想添加一个方法来返回格式为mm:ss(如09:08)的时间。我已经做了一个方法来实现这一点,并使用irb进行了测试。但是,当我试图从视图中访问该值时,看起来实例变量没有被初始化,所有值的值都是“00:00”。在这里和其他地方,看起来我可以创建一个类方法(通过添加self)并将值传递给格式化,但这似乎是多余的。模型实例应该已经有了数据。使用类方法是ruby方式吗?还是我在做其他明显错误的事情Ruby on rails 我可以对rails模型中的计算值使用实例方法吗?,ruby-on-rails,ruby,Ruby On Rails,Ruby,我有一个模型,它的数据中有一个时间长度(分和秒列)。我想添加一个方法来返回格式为mm:ss(如09:08)的时间。我已经做了一个方法来实现这一点,并使用irb进行了测试。但是,当我试图从视图中访问该值时,看起来实例变量没有被初始化,所有值的值都是“00:00”。在这里和其他地方,看起来我可以创建一个类方法(通过添加self)并将值传递给格式化,但这似乎是多余的。模型实例应该已经有了数据。使用类方法是ruby方式吗?还是我在做其他明显错误的事情 class Segment < Applic
class Segment < ApplicationRecord
belongs_to :course
def time
m = pad @min
s = pad @sec
m + ":" + s
end
def pad(x)
x.to_s.rjust(2,"0")
end
end
view:
<%= segment.time %> # returns 00:00
<%= segment.min %>:<%= segment.sec %> # returns correct non-padded values
类段
我正在使用Rails 5.0.1和Ruby 2.2.6p386。为什么要尝试使用实例变量?如果
min
和sec
是表中的列,您可以直接使用它们(隐式接收器将是self
,因此这是表示self.min
和self.sec
的较短方式)
这应该起作用:
def time
"#{pad(min)}:#{pad(sec)}"
end
一般来说,尽管我建议您考虑使用helpers和/或decorator,但您现在所做的是在模型中添加两种方法,它们仅用于显示目的。问题在于,您试图访问ActiveRecord属性时,假设每个数据字段都存储在一个实例变量中。这不起作用,因为属性作为
ActiveRecord::AttributeSet
结构存储在@attributes
中
您可以使用segment.instance\u method\u get(:@attributes)
在这个结构中操作原始数据相当麻烦。所以AR为类中的每个属性定义属性方法。在您的例子中,#min
,#min=
或#sec
,#sec=
(以及一系列其他方法)
最好通过访问器方法访问数据,而不是直接访问实例变量。无论是从类内部还是外部调用该方法,这都是正确的
如果在类之外调用该方法,则需要显式地声明访问器方法的接收者,该方法将是您的段
对象
segment.min
在您的类中,接收方隐式定义为self
(正如Michael Kohl提到的),因此您可以使用
class Segment
def padded_min
min to_s.rjust(2,"0")
end
end
隐式定义对于以=
结尾的方法有点不同——Ruby假设您正在创建一个局部变量。如果试图调用setter方法,则需要显式定义接收方
class Segment
def update_time(time)
self.time = (time)
end
end
有一种更优雅的方法来处理时间长度 只需使用一个整数列,并以所需的最小精度级别(秒)存储持续时间。在本例中,我们调用列
duration
class Segment < ApplicationRecord
# custom getter which returns an ActiveSupport::Duration
def duration
self[:duration].seconds
end
def duration_as_time
Time.at(self[:duration]).utc
end
def time
duration_as_time.strftime("%M:%S")
end
end
拥有一个时间对象可以让我们使用专门构建的方法,比如strftime
,而不是重新发明轮子
尽管可以说格式化时间不是模型的工作,应该由助手或装饰师来处理。如果您是不了解区域设置的模型,则尤其如此。我认为实例变量不是问题所在。我猜这与你在
时间中构建字符串的方式有关。正如答案所示,尝试字符串插值。就类方法而言,您可以编写整个程序,将所有内容作为参数传递,而不存储实例状态。Thid需要更长的编写时间,但是让每个方法都是自包含的可以帮助解耦代码。最好的办法是尝试两种方法,看看你喜欢哪一种。你已经解决了我困惑的根源!非常感谢你!非常感谢。我一定会用它来重构我所拥有的。
irb(main):025:0> Time.at(360).utc
=> 1970-01-01 00:06:00 UTC