Как бы вы могли сохранить рабочее время в db/model приложения Rails?

Я создаю приложение Rails, которое будет хранить часы открытия и закрытия для бизнеса. Первоначально я думал просто использовать текстовый тип данных и позволить ему быть свободным:

"Monday to Friday 9am to 5pm
Saturday 11am to 4pm
Closed Sundays"

Но требования изменились, и мне нужно проверить часы на текущую дату и время и отобразить "Открыть" или "Закрыто" в представлении. Что-то вроде:

class Business < ActiveRecord::Base

  def open?
    # Something like ... 
    Time.now > open_time && Time.now < close_time
  end

end

Итак, что было бы лучшим способом справиться с этим с точки зрения хранения часов для каждого дня недели? Должен ли бизнес просто has_many: open_blocks (или что-то еще), имеющее открытые и закрытые времена? Должен ли я просто хранить этот день в виде строки?

Ответы

Ответ 1

Это было связано с недавним RubyLearning задача - может быть полезно:)

Ответ 2

В настоящее время я настраиваю список каталогов для клиента, и мы хотим предоставить пользователю большую гибкость. Итак: пусть пользователь настраивает блоки в течение нескольких дней:

У нас есть день (целое число 1-7), открывается (время), закрывается (время), а некоторые магазины или достопримечательности лето и зима, или они делают отпуск. Согласно schema.org, вы должны добавить valid_from (datetime) и valid_through (datetime).

С помощью этой настройки пользователь может создать все, что захочет:

# migration
class CreateOpeningHours < ActiveRecord::Migration
  def change
    create_table :opening_hours do |t|
      t.integer :entry_id # your model reference
      t.integer :day
      t.time :closes
      t.time :opens
      t.datetime :valid_from
      t.datetime :valid_through
    end
  end
end

Пример для модели:

class OpeningHour < ActiveRecord::Base

  belongs_to :entry

  validates_presence_of :day, :closes, :opens, :entry_id
  validates_inclusion_of :day, :in => 1..7
  validate :opens_before_closes 
  validate :valid_from_before_valid_through 

  # sample validation for better user feedback
  validates_uniqueness_of :opens, scope: [:entry_id, :day]
  validates_uniqueness_of :closes, scope: [:entry_id, :day]

  protected
  def opens_before_closes
    errors.add(:closes, I18n.t('errors.opens_before_closes')) if opens && closes && opens >= closes
  end

  def valid_from_before_valid_through
    errors.add(:valid_through, I18n.t('errors.valid_from_before_valid_through')) if valid_from && valid_through && valid_from >= valid_through
  end

end

С помощью этой установки вы можете легко создать is_open? метод в вашей модели. В настоящее время я не настроил is_open? метод, но если кому-то нужно, дайте мне хит! Думаю, я закончу его в ближайшие дни.

Ответ 3

В этом случае я, вероятно, сделаю что-то реляционное, возможно, с ИППП, если вы хотите иметь определенные дни, когда бизнес закрыт (например, разовые закрытия). Вот пример базового ИППП:

class Business < ActiveRecord::Base
  has_many :open_time_blocks
  has_many :closed_time_blocks

  def open?(time)
    # false if time is "inside" any of the closed_time_blocks
    # else is true if inside any of the open_time_blocks
    # else is false
  end

  def closed?(time)
    !open?
  end
end

# == Schema Information
#
# Table name: time_blocks
#
#  id          :integer         not null, primary key
#  business_id :integer
#  type        :string(255)
#  start_at    :datetime
#  end_at      :datetime
#  created_at  :datetime
#  updated_at  :datetime
class TimeBlock < ActiveRecord::Base
  belongs_to :business
end

class OpenTimeBlock < TimeBlock; end
class ClosedTimeBlock < TimeBlock; end

Ответ 4

Я бы сказал, что рабочие часы принадлежат партовому адресу и должны быть представлены RFC 5455 RRULE и необязательно EXRULE или EXDATE s.

Скажем, у вас есть партия:

"Acme, Inc."

У них есть один физический адрес:

"123 Main Street, Ванкувер"

Их адрес выполняет две роли:

"Продажи" и "Сервис"

Продажи открыты Mo-Sa 10-8, а сервис открыт Mo-Fr 9-5

Это RRULES:

(продажи)

startTime:'10:00:00'
endTime:'20:00:00'
RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR,SA

(Сервис)

startTime:'09:00:00'
endTime:'17:00:00'
RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR

Ответ 5

Оформить заказ эти библиотеки для обработки повторяющихся дат.

Как только рекурсия устанавливается в объекте say office_hours, в ice_cube вы можете запросить его как:

office_hours.occurring_at?(Time.now)

Ответ 6

Итак, я только что узнал, что ice_cube может обрабатывать повторяющиеся длительности:

> schedule = IceCube::Schedule.new(Time.now, :duration => 3600)
> schedule.add_recurrence_rule Rule.daily
> schedule.occurs_at?(Time.now + 1000)
true
> schedule.occurs_at?(Time.now + 1.day + 1000)
true
> schedule.occurs_at?(Time.now + 4000)
false

Я подозреваю, что вы можете обрабатывать множество разных ситуаций, используя ice_cube таким образом.

Кстати, я реализую аналогичный открытый/закрытый график работы. Мне было бы интересно узнать, как вы это сделали, и если у вас есть репозиторий github, мы можем сотрудничать вместе.