Ruby on rails 可以在Rails中有条件地链接作用域吗?

Ruby on rails 可以在Rails中有条件地链接作用域吗?,ruby-on-rails,Ruby On Rails,考虑以下代码: 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

考虑以下代码:

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

有没有一种方法可以有条件地链接这些范围,如车、蓝、手动、豪华等?也就是说,如果arg为true,则只有作用域?

可以有条件地应用ActiveRecord作用域,如下所示:

scope :blue, -> { where(color: 'blue') if condition }
Task.blue(color == 'blue')
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])
其中,
条件
是您定义的返回true或false的内容。如果条件返回true,则应用范围。如果条件为false,则忽略范围

您还可以将值传递到范围:

scope :blue, ->(condition) { where(color: 'blue') if condition }
所以,你可以这样做:

scope :blue, -> { where(color: 'blue') if condition }
Task.blue(color == 'blue')
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])
这与OP要求的类似。但是,你为什么要这么做

更好的方法是这样的:

scope :blue, -> { where(color: 'blue') if condition }
Task.blue(color == 'blue')
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])
可以这样称呼:

scope :blue, -> { where(color: 'blue') if condition }
Task.blue(color == 'blue')
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])

您的里程数可能会有所不同。

您可以使用ruby 2.5中为其添加的新功能yield\u self()

在您的示例中:

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

你已经做的事情有什么问题吗?我想这应该行得通。我想在一行中创建一个查询,而不是调用每个函数并在每个步骤存储部分结果。你不是在存储部分结果,而是在一步一步地创建查询。在您尝试对需要结果的
cars
执行某些操作之前,不会命中数据库(即没有部分结果或其他结果)。