如何使用rails作用域或where子句来查询OR AND条件

时间:2017-09-30 10:39:22

标签: sql ruby-on-rails

所以我正在尝试查询看起来像这样的

Car Model
has_many :colors
scope :for_cars, ->(color) { Car.join(:color).where(colors: { name: color}) }

对于greenblue的汽车,我可以这样做。

Car.for_cars(['green', 'blue'])

我希望获得greenblue的汽车,我该怎么做?

我正在使用postgres。

3 个答案:

答案 0 :(得分:2)

以这种方式查询: -

scope :for_cars, ->(color) { Car.joins(:colors).where("colors.name" =>  color) }

in this way much simpler:-

scope :for_cars, ->(color) { Car.joins(:colors).where("colors.name":  color) }

in this way also if this scope is in Car model:-

scope :for_cars, ->(color) { joins(:colors).where("colors.name":  color) }

注意: - Tested in Rails 4.2.9

检查Rails guides on joins

答案 1 :(得分:0)

Car.for_cars('green').merge(Car.for_cars('blue'))

这将生成具有两个连接和返回交集的单个查询。 https://apidock.com/rails/v4.2.7/ActiveRecord/SpawnMethods/merge

但随着所需颜色数量的增加(连接数量太多),这种方法无效。

您也可以这样做:

wanted_colors = ['green', 'blue', 'red', 'yellow']

Car.for_cars(wanted_colors).group("cars.id").having("COUNT(colors.id) = #{wanted_colors.size}")

根据您使用的RDBMS,此approuch可能会推迟。

答案 2 :(得分:0)

在没有范围的情况下实现这一目标的一种方法是在Car上使用方法:

def color_names
  colors.map(&:name)
end

def has_all_color_names(has_color_names = [])
  (color_names & has_color_names).size == has_color_names.size
end

def self.has_all_color_names(has_color_names = [])
  includes(:colors).select { |car| car.has_all_color_names has_color_names }
end

......然后......

Car.has_all_color_names %w(Green Blue)