如何从数组中使用“ OR”子句动态调用作用域

时间:2018-08-27 13:46:01

标签: ruby-on-rails rails-activerecord

我有一个数组,我想用OR子句调用作用域:

cars = ['bmw', 'audi', 'toyota']

class Car < AR
  scope :from_bmw, -> { where(type: 'bmw') }
  scope :from_audi, -> { where(type: 'audi') }
  scope :from_toyota, -> { where(type: 'toyota') }
end

我想实现以下目标:

Car.from_bmw.or(Car.from_audi).or(Car.from_toyota)

我的cars数组可以更改;如果是cars = ['toyota', 'audi'],我的方法应产生:

Car.from_toyota.or(Car.from_audi)

我有如下内容:

def generate(cars)
  scopes = cars.map {|f| "from_#{f} "}

  scopes.each do |s|
    # HOW TO I ITERATE OVER HERE AND CALL EACH SCOPE???
  end
end

我不想将type作为范围的参数传递,这是有原因的。

2 个答案:

答案 0 :(得分:1)

def generate(cars)
  return Car.none if cars.blank?
  scopes = cars.map {|f| "from_#{f} "}

  scope = Car.send(scopes.shift)

  scopes.each do |s|
    scope = scope.or(Car.send(s))
  end

  scope
end

答案 1 :(得分:1)

假设给定的数组仅包含有效的type值,则可以简单地做到这一点:

class Car
  scope :by_type, -> (type) { where(type: type) }
end

types = ['bmw', 'audi', 'toyota']

Car.by_type(types) # => It'll generate a query using IN: SELECT * FROM cars WHERE type IN ('bmw', 'audi', 'toyota')

如果出于任何原因都不希望将数组作为范围的参数传递,则可以创建一个将数组值映射到有效by_type参数的哈希值。

VALID_CAR_TYPES = { volkswagen: ['vw', 'volkswagen'], bmw: ['bmw'], ...  }
def sanitize_car_types(types)
  types.map do |type|
    VALID_CAR_TYPES.find { |k, v| v.include?(type) }.first
  end.compact
end


Car.by_type(sanitize_car_types(types))