考虑名为ActiveRecord
的{{1}}模型,其持续时间属性以分钟为单位表示电影的长度。在我的视图中打印此属性的最佳方法是什么?
我希望能够写出这样的内容:
Movie
但如果我能写一下,那就更棒了:
= l(@movie.duration, unit: :minutes) # Should return "105 minutes"
甚至
= l(@movie.duration)
但是,这需要某种方式来声明持续时间属性中使用的单位,该属性只是数据库中的整数。
似乎Rails I18n有一种翻译属性的方法,但只有他们的名字,而不是他们的价值。
最好与I18n配合使用的解决方案。
答案 0 :(得分:2)
Rails不知道该值是以分钟为单位。
此功能属于帮助器,或(我的偏好)装饰器,带有I18N标签。
答案 1 :(得分:0)
我认为没有理由让这里的事情复杂化;你甚至不在不同的单位之间转换:
在您看来:
<%= t :'models.movie.duration', :count => @movie.duration %>
在config/locales/en.yml
en:
models:
movie:
duration:
one: '%{count} minute'
other: '%{count} minutes'
答案 2 :(得分:0)
大约7年前,我问了这个问题,但是仍然偶尔有活动。
因此对于那些像我一样思考此主题的(初级)开发人员,我想补充一些想法。
我认为这个问题试图解决多个问题。第一个问题是PostgreSQL没有本地数据类型来存储持续时间(至少我不熟悉)。
结果,当使用持续时间时,我们被迫在持续时间和PostgreSQL提供的数据类型之间进行转换。就我而言,我使用了整数类型。
因此,有两个后续问题。
我会说整数或十进制。这取决于应用程序的需求和数据的质量。如果您希望以分钟为单位存储,但需要(milli)秒精度,请使用十进制。但总的来说,我发现使用整数更容易,因此最好使用足够小的单位,以使整数足够精确。
根据您要如何使用数据,我认为最好封装有关持续时间如何转换为数据库数据类型的知识,而不是将其泄漏到应用程序的视图(和其他地方)中。如果这些知识泄漏了,那么以后更改基础数据类型将变得更加困难-例如,如果PostgreSQL / Rails添加了更好的数据类型。
所以我可能会制作一个value class。这意味着制作一个使用数据库值初始化的持续时间类,但可以将其查询和修改为持续时间。
简单的例子:
class Duration
attr_accessor :seconds
def initialize(seconds)
@seconds = seconds
end
def minutes
(seconds / 60.0).round
end
def minutes=(minutes)
self.seconds = minutes * 60
end
def hours
(seconds / (60.0 * 60)).round
end
def hours=(hours)
self.seconds = hours * 60 * 60
end
def to_s(unit = :minutes) # Valid values are :seconds, :minutes and :hours.
I18n.t("value_classes.duration.units.#{unit}", value: send(unit))
end
end
如果将其与ActiveRecord类上的自定义访问器结合使用,那么您将获得相当可靠的封装。
class Movie < ApplicationRecord
def duration
Duration.new(duration_in_seconds) # Name of database attribute
end
def duration=(duration_instance)
self.duration_in_seconds = duration_instance.seconds
end
end
在视图中:
<p>Duration: <%= @movie.duration %></p>
您可能希望向Duration类添加一些其他格式设置方法,因此可以根据设计者在特定情况下的需要,在“ 127分钟”,“ 2小时7分钟”和“ 2:07”之间进行选择。视图。
此解决方案还包含访问器,因此您的控制器可以执行类似的操作
@movie.duration = Duration.new.tap do |duration|
duration.minutes = params[:movie][:duration_as_minutes]
end