Использование поля длительности в модели Rails - PullRequest
27 голосов
/ 27 июня 2009

Я ищу лучший способ использовать поле длительности в модели Rails. Я бы хотел, чтобы формат был ЧЧ: ММ: СС (например, 01:30:23). Используемая база данных - это sqlite локально и Postgres в производстве.

Я также хотел бы поработать с этим полем, чтобы я мог взглянуть на все объекты в поле и определить общее время всех объектов в этой модели и получить что-то вроде:

30 записей на общую сумму 45 часов, 25 минут и 34 секунды.

Так, что лучше всего подойдет?

  • Тип поля для миграции
  • Поле формы для форм CRUD (часы, минуты, секунды выпадающие?)
  • Наименее дорогой метод генерации общей длительности всех записей в модели

Ответы [ 4 ]

41 голосов
/ 27 июня 2009
  • Хранить как целые числа в вашей базе данных (вероятно, количество секунд).
  • Ваша форма заявки будет зависеть от конкретного варианта использования. Раскрытия болезненны; лучше использовать небольшие текстовые поля для длительности в часах + минутах + секундах.
  • Просто выполните запрос SUM по столбцу длительности, чтобы получить общий итог. Если вы используете целые числа, это легко и быстро.

Дополнительно:

  • Используйте помощника для отображения продолжительности ваших просмотров. Вы можете легко преобразовать длительность в виде целого числа секунд в ActiveSupport::Duration, используя 123.seconds (замените 123 на целое число из базы данных). Используйте inspect для полученного Duration для хорошего форматирования. (Это не идеально. Вы можете написать что-нибудь сами.)
  • В вашей модели вам, вероятно, понадобятся средства чтения и записи атрибутов, которые возвращают / берут ActiveSupport::Duration объекты, а не целые числа. Просто определите duration=(new_duration) и duration, которые внутренне вызывают read_attribute / write_attribute с целочисленными аргументами.
9 голосов
/ 27 июля 2017

В 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
5 голосов
/ 01 февраля 2011

Я пытался использовать ActiveSupport :: Duration, но не смог получить четкий вывод.

Вам может понравиться ruby-duration , неизменный тип, представляющий некоторое количество времени с точностью в секундах. Он имеет множество тестов и тип поля модели Mongoid.

Я хотел также легко разобрать строки длительности человека, поэтому я выбрал Хроническая длительность . Вот пример добавления его в модель, которая имеет поле time_spent в секундах.

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
3 голосов
/ 12 сентября 2014

Я написал заглушку для поддержки и использования типа interval PostgreSQL как ActiveRecord::Duration.

Смотрите эту суть (вы можете использовать ее в качестве инициализатора в Rails 4.1): https://gist.github.com/Envek/7077bfc36b17233f60ad

Также я открыл пулл-запросы к Rails: https://github.com/rails/rails/pull/16919

...