在Rails模型中使用持续时间字段
我正在寻找在Rails模型中使用持续时间字段的最佳方法。 我希望格式为HH:MM:SS(例如:01:30:23)。 正在使用的数据库是本地的sqlite和生产中的Postgres。
我还想使用这个字段,这样我就可以看一下该字段中的所有对象,并得出该模型中所有对象的总时间,最后得到如下结果:
30条记录共计45小时25分34秒。
那么什么最适合?
- 迁移的字段类型
- CRUD表单的表单字段(小时,分钟,第二次下拉?)
- 生成模型中所有记录的总持续时间的最便宜的方法
- 在数据库中以整数存储(可能是秒数)。
- 您的报名表将取决于具体的用例。 下拉令人痛苦; 最好在小时+分钟+秒内使用小文本字段。
- 只需在持续时间列上运行
SUM
查询即可生成总计。 如果使用整数,这很容易,也很快。
另外:
- 使用帮助程序在视图中显示持续时间。 您可以使用
123.seconds
轻松地将持续时间作为整数秒转换为ActiveSupport::Duration
(将123
替换为数据库中的整数)。 对结果的Duration
使用inspect
以获得良好的格式。 (这不完美。你可能想自己写点东西。) - 在您的模型中,您可能希望属性读取器和编写器返回/获取
ActiveSupport::Duration
对象,而不是整数。 只需定义duration=(new_duration)
和duration
,它在内部使用整数参数调用read_attribute
/read_attribute
。
在Rails 5中,您可以使用ActiveRecord :: Attributes将ActiveSupport :: Durations存储为ISO8601字符串。 使用ActiveSupport :: Duration而不是整数的优点是,您可以立即使用它们进行日期/时间计算。 你可以做一些像Time.now + 1.month
这样的事情,它总是正确的。
这是如何做:
添加config/initializers/duration_type.rb
class DurationType < ActiveRecord::Type::String def cast(value) return value if value.blank? || value.is_a?(ActiveSupport::Duration) ActiveSupport::Duration.parse(value) end def serialize(duration) duration ? duration.iso8601 : nil end end ActiveRecord::Type.register(:duration, DurationType)
移民
create_table :somethings do |t| t.string :duration end
模型
class Something < ApplicationRecord attribute :duration, :duration end
用法
something = Something.new something.duration = 1.year # 1 year something.duration = nil something.duration = "P2M3D" # 2 months, 3 days (ISO8601 string) Time.now + something.duration # calculation is always correct
我尝试使用ActiveSupport :: Duration但是无法清除输出。
你可能喜欢ruby-duration ,一种不可变的类型,代表一些精确的时间,以秒为单位。 它有很多测试和Mongoid模型字段类型。
我还想轻松解析人类的持续时间字符串,所以我选择了慢性持续时间 。 以下是将其添加到具有time_spent in seconds字段的模型的示例。
class Completion < ActiveRecord::Base belongs_to :task belongs_to :user def time_spent_text ChronicDuration.output time_spent end def time_spent_text= text self.time_spent = ChronicDuration.parse text logger.debug "time_spent: '#{self.time_spent_text}' for text '#{text}'" end end
我写了一些存根来支持和使用PostgreSQL的interval
类型作为ActiveRecord::Duration
。
请参阅此要点(您可以在Rails 4.1中将其用作初始化程序): https : //gist.github.com/Envek/7077bfc36b17233f60ad
我也在那里打开了对Rails的拉取请求: https : //github.com/rails/rails/pull/16919