How would you store a business's hours in the db/model of a Rails app?

后端 未结 5 748
余生分开走
余生分开走 2021-01-31 05:43

I\'m creating a Rails app that will store the opening and closing hours for a business. Originally, I thought of simply using a text data type and letting it be free-form:

相关标签:
5条回答
  • 2021-01-31 06:13

    I'm currently setting up a directory listing for a client and we want give the user more flexibility. So: Let the user set up blocks for days:

    We have a day (integer 1-7), opens (time), closes (time) and some shops or sights have summer and winter opening times, or they make vacations. According to schema.org you have to add a valid_from (datetime) and a valid_through (datetime).

    With this setup the user can create whatever he wants:

    # 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
    

    Example for the model:

    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
    

    With that setup you can create easily a is_open? method in your model. Currently I did not setup the is_open? method, but if somebody needs, give me a hit! I think I will finish it in the next days.

    0 讨论(0)
  • 2021-01-31 06:16

    I would say that Operating Hours belong to a Party Address, and should be represented by an RFC 5455 RRULE and optionally an EXRULE or EXDATEs.

    Let's say you have a Party:

    "Acme, Inc."

    They have one PhysicalAddress:

    "123 Main Street, Vancouver"

    Their address plays two roles:

    "Sales" and "Service"

    Sales is open Mo-Sa 10-8 and Service is open Mo-Fr 9-5

    These are the RRULES:

    (Sales)

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

    (Service)

    startTime:'09:00:00'
    endTime:'17:00:00'
    RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR
    
    0 讨论(0)
  • 2021-01-31 06:22

    In this case, I would probably do something relational, perhaps with STI if you wanted to have certain days where the business is closed (e.g. non-recurring closings). Here's a basic STI example:

    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
    
    0 讨论(0)
  • 2021-01-31 06:24

    Checkout these libraries for handling recurring dates.

    Once the recurrence is setup in an object say office_hours, in ice_cube you can query it as:

    office_hours.occurring_at?(Time.now)
    
    0 讨论(0)
  • 2021-01-31 06:37

    So I just found out ice_cube can handle recurring durations:

    > 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
    

    I suspect that you can handle a lot of different situations using ice_cube in this manner.

    Incidentally, I'm implementing a similar open/closed business schedule. I'd be interested to know how you've done it, and if you have a github repo we can collaborate on together.

    0 讨论(0)
提交回复
热议问题