子关联的多个条件的活动记录查询

Active record query for multiple conditions on child association

我需要有关相关子查询的帮助。

一个项目有很多方面。 facet 的属性是 identifiercontent。 facet identifiercontent 用于提供选项来过滤显示的项目 - 例如,identifier 可以是 'color' 而 content 'red' 或 identifier 是 'size' 而 content 是 '10`

我想要一个查询 return

所在的项目
(label contains a search term) 

OR 
( has a facet with an identifier equal to one of 2 given values AND the content includes the search term) 

AND 
(it ALSO has ANOTHER facet whose identifier is equal to one of a number of some different values AND content equal to one of a number of yet more different values).

我试过的 rails 查询

rails查询

items.joins(:facets)
  .where('items.label LIKE ? OR facets.identifier LIKE ?', "%#{search_term}%", "%#{search_term}%")
  .where('facets.identifier' => filter).where('facets.content' => value).uniq

转换为以下 sql 查询

SELECT DISTINCT (`items`.`id`) FROM `items` INNER JOIN `facets` ON 
`facets`.`item_id` = `items`.`id` AND `facets`.`identifier` IN ('summary', 'description') AND 
(items.label LIKE '%outing%' OR facets.content LIKE '%outing%') AND 
`facets`.`identifier` = 'color' AND `facets`.`content` IN 
('red')

这个return是一个空数组,因为我认为

之间存在冲突
`facets`.`identifier` IN ('summary', 'description')

`facets`.`identifier` = 'color'

如何编写一个查询,使 return 一个项目基于其多个方面。是否可以将其写为活动记录而不是原始 sql?

我确定了一种可行的方法,但不一定是最佳方法:

class ItemProvider

  attr_reader :keyword, :filters

  FACET_CONTENT_TO_SEARCH = %w[summary description]

  def initialize(keyword, filters)
    @keyword = keyword
    @filters = filters
  end

  def retrieve
    @items = Item.all

    filter_by_keyword
    filter_items
  end

  private

  def filter_by_keyword
    return @items if keyword.blank?

    @items = @items
      .joins(:facets)
      .where('facets.identifier' => FACET_CONTENT_TO_SEARCH)
      .where('items.label LIKE ? OR facets.content LIKE ?', "%#{keyword}%", "%#{keyword}%").uniq
  end

  def filter_items
    return @items if filters.blank?

    filters_to_hash.each do |filter, value|
      @items = Item
      .unscoped
      .select("items.*")
      .joins("INNER JOIN facets ON facets.facetable_id = items.id AND facets.facetable_type = 'Item'")
      .where('facets.identifier' => filter)
      .where('facets.content' => value)
    end
  end

  def filters_to_hash
    filters.reduce({}) do |acc, filter|
      if acc[filter[:identifier]]
        acc[filter[:identifier]] << filter[:value]
      else
        acc[filter[:identifier]] = [filter[:value]]
      end
      acc
    end
  end
end