I'm looking for the best way to use a duration field in a Rails model. I would like the format to be HH:MM:SS (ex: 01:30:23). The database in use is sqlite locally and Postgres in production.
I would also like to work with this field so I can take a look at all of the objects in the field and come up with the total time of all objects in that model and end up with something like:
30 records totaling 45 hours, 25 minutes, and 34 seconds.
So what would work best for?
SUM
query over the duration column to produce a grand total. If you use integers, this is easy and fast.Additionally:
ActiveSupport::Duration
by using 123.seconds
(replace 123
with the integer from the database). Use inspect
on the resulting Duration
for nice formatting. (It is not perfect. You may want to write something yourself.)ActiveSupport::Duration
objects, rather than integers. Simply define duration=(new_duration)
and duration
, which internally call read_attribute
/ write_attribute
with integer arguments.In Rails 5, you can use ActiveRecord::Attributes to store ActiveSupport::Durations as ISO8601 strings. The advantage of using ActiveSupport::Duration over integers is that you can use them for date/time calculations right out of the box. You can do things like Time.now + 1.month
and it's always correct.
Here's how:
Add 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)
Migration
create_table :somethings do |t| t.string :duration end
Model
class Something < ApplicationRecord attribute :duration, :duration end
Usage
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With