Подтвердить что ты не робот

Использование поля продолжительности в модели Rails

Я ищу лучший способ использовать поле продолжительности в модели Rails. Я бы хотел, чтобы формат был HH: MM: SS (ex: 01:30:23). В используемой базе данных используется локальная база данных sqlite и Postgres.

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

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

Так что будет лучше всего работать?

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

Ответ 1

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

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

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

Ответ 2

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

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

Я также хотел легко разбирать строки продолжительности жизни, поэтому я пошел с Chronic Duration. Вот пример добавления его в модель с полем 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

В 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

Model

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

Ответ 4

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

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

Кроме того, я открыл запросы на загрузку Rails: https://github.com/rails/rails/pull/16919