Как динамически вызывать области с предложением 'OR' из массива - PullRequest
0 голосов
/ 27 августа 2018

У меня есть массив, и я хотел бы вызвать области с помощью предложения 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

Я не хочу передавать тип в качестве аргумента для видимости, есть причина этого.

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Предполагая, что данный массив содержит только допустимые 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))
0 голосов
/ 27 августа 2018
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
...