Nacho
Nacho

Reputation: 1009

Rails scope using instance method

You have a model Store with an attribute time_zone(New York, London, Tokyo, etc.).

All stores are open from 8am to 9pm in their local time zone.

You have an instance method to check if the store is currently open:

def currently_open?
  current_store_time = Time.now.in_time_zone(time_zone)
  (8...21).cover? current_store_time.hour
end

How do you create a rails scope for all currently open stores using the Store#currently_open? instance method (or without that method, but I want to use the rails scope syntax).

scope :currently_open, -> { "use Store#currently_open? here" }

Upvotes: 0

Views: 707

Answers (2)

Yana Agun Siswanto
Yana Agun Siswanto

Reputation: 2032

Does this works for you?

scope :with_current_store_time, -> {
  select(all.arel.projections, "date_part('hour', NOW() at time zone time_zone) as current_store_time")
}
scope :currently_open, -> {
  with_current_store_time.where(current_store_time: 8..21)
}

Basically I rewrote current_store_time as a scope (with_current_store_time)

I answered this using these as references:

Notes :

  1. current_store_time probably not describing the actual value being calculated.

  2. current_store_time is returning hour, on the specified timezone.

Upvotes: 3

Stefan
Stefan

Reputation: 114138

If your table only contains a time_zone string which contains a valid Rails time zone name (or alias), you'll have to somehow generate a list of time zone names that are currently between 8 am and 9 pm.

To do so, you could write a helper method that fetches the used time zones in your table via Store.distinct.pluck(:time_zone) and selects those that match the criteria:

class Store
  def self.time_zones_between(hours)
    distinct.pluck(:time_zone).select do |time_zone|
      Time.use_zone(time_zone) { hours.cover?(Time.current.hour) }
    end
  end

  scope :currently_open, -> { where(time_zone: time_zones_between(8...21) }
end

Note that calling Store.currently_open will result two queries: one to get the time zones and one to fetch the actual results. You can avoid the first query by providing the list of available time zones yourself.

Upvotes: 1

Related Questions