2009-06-26 4 views
27

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

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

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

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

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

ответ

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

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

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

+1 для публикации моего же комментария за меньшее время, чем я! :) –

+0

Я никогда не рассматривал использование секунд, ну! Спасибо за совет! – mwilliams

+0

Как вы используете 'inspect' для форматирования вывода? Пример? –

5

Я пробовал использовать 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

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

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

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

+0

Мы написали обновленную версию для Rails 5.1: https://gist.github.com/vollnhals/a7d2ce1c077ae2289056afdf7bba094a –

4

В Rails 5, вы можете использовать ActiveRecord :: Атрибуты для хранения ActiveSupport :: длительностям как строки 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