Scope with multiple where conditions based on mult

2019-08-19 01:23发布

问题:

Is there possible to use something like

  scope :state, ->(state) {
    merge(where("start_time <= ? and end_time >= ?", Time.now.utc.beginning_of_day, Time.now.utc.beginning_of_day)) if state.include?("open")
    merge(where("end_time < ?", Time.now.utc.beginning_of_day)) if state.include?("closed")
    merge(where("start_time > ?", Time.now.utc.beginning_of_day)) if state.include?("upcoming")
  }

If I use this scope, only the last one is functional.

for example:

  • state(["upcoming"]) -> work
  • state(["open"]) -> where is not used
  • state(["deleted"], ["upcoming"]) -> only where with upcoming conditions is used

回答1:

hope this solve your problem.

scope :state, ->(state) {where(self.query_conditions(state), q: Time.now.utc.beginning_of_day))}

def self.query_conditions(state)
  q = ""
  q+= "start_time <= :q and end_time >= :q" if state.include?("open")
  q+= " and end_time < :q" if state.include?("closed")
  q+= " and start_time > :q" if state.include?("upcoming")
  q
end


回答2:

You should be able to use

  scope :state, ->(state) {
    rel = all
    rel = rel.where("start_time <= ? and end_time >= ?", Time.now.utc.beginning_of_day, Time.now.utc.beginning_of_day) if state.include?("open")
    rel = rel.where("end_time < ?", Time.now.utc.beginning_of_day) if state.include?("closed")
    rel = rel.where("start_time > ?", Time.now.utc.beginning_of_day) if state.include?("upcoming")
    rel
  }

Notice that you should do

state(["deleted", "upcoming"])

instead of

state(["deleted"], ["upcoming"])

Also you can use Array.wrap to simplify using the scope:

  scope :state, ->(state) {
    state = Array.wrap(state)
    rel = all
    rel = rel.where("start_time <= ? and end_time >= ?", Time.now.utc.beginning_of_day, Time.now.utc.beginning_of_day) if state.include?("open")
    rel = rel.where("end_time < ?", Time.now.utc.beginning_of_day) if state.include?("closed")
    rel = rel.where("start_time > ?", Time.now.utc.beginning_of_day) if state.include?("upcoming")
    rel
  }

With state being wrapped you can use the scope in both following ways:

Model.state(['open', 'upcoming'])
Model.state('open', 'upcoming')