考虑以下代码:
class Car
scope :blue, -> { where(color: "blue") }
scope :manual, -> { where(transmission: "manual") }
scope :luxury, -> { where("price > ?", 80000) }
end
def get_cars(blue: false, manual: false, luxury: false)
cars = Car.all
cars = cars.blue if blue
cars = cars.manual if manual
cars = cars.luxury if luxury
end
是否可以有条件地像Car.blue.manual.luxury
那样链接这些范围?即仅当arg为true时才作用域?
答案 0 :(得分:2)
您可以使用 yield_self (read more here),它是ruby 2.5中添加的新功能。
在您的示例中:
class Car
scope :blue, -> { where(color: "blue") }
scope :manual, -> { where(transmission: "manual") }
scope :luxury, -> { where("price > ?", 80000) }
end
def get_cars(blue: false, manual: false, luxury: false)
cars = Car.all
.yield_self { |cars| blue ? cars.blue : cars }
.yield_self { |cars| manual ? cars.manual : cars }
.yield_self { |cars| luxury ? cars.luxury : cars }
end
答案 1 :(得分:1)
ActiveRecord范围可以有条件地应用,如下所示:
scope :blue, -> { where(color: 'blue') if condition }
您定义condition
的地方返回true或false。如果条件返回true,则应用范围。如果条件为假,则范围将被忽略。
您还可以将值传递给范围:
scope :blue, ->(condition) { where(color: 'blue') if condition }
因此,您可以执行以下操作:
Task.blue(color == 'blue')
与OP要求的内容相似。但是,为什么呢?
更好的方法是这样的:
scope :color, ->(color) { where(color: color) if color.present? }
将这样称呼:
Car.color('blue') # returns blue cars
Car.color(nil) # returns all cars
Car.color(params[:color]) # returns either all cars or only cars of a specific color, depending on value of param[:color]
Car.color(params[:color]).transmission(params[:transmission]).price(params[:price])
您的里程可能会有所不同。