在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