Rails Arel, выберите из одного столбца, но несколько значений

У меня есть стол cherry_picker_cherries, Эти записи полиморфно принадлежат модели под названием Pickable, Они могут иметь несколько записей в таблице для одного и того же выбора, но он всегда имеет разные cherry_pick_id,

Моя проблема: у меня есть вишня под названием Favorite Tree и отдельный cherry_pick называется Favorite Fruit, Я хочу быть в состоянии отфильтровать коллекцию сборов по нескольким вишневым киркам. Например, я хочу найти все кирки, у которых есть любимое дерево cherry И есть любимый фрукт orange,

Я могу сделать это ужасным образом, используя следующее:

CherryPicker::Cherry.find_by_sql("SELECT * from cherry_picker_cherries t1 JOIN cherry_picker_cherries t2 USING(pickable_id) WHERE t1.value = 'orange'AND t2.value = 'cherry'")

Однако у этого подхода есть несколько недостатков. Он не справляется даже с Cherry Picks, только два прямо сейчас. Кроме того, результирующий набор преобразуется в массив, но мне нужно вернуть отношение ActiveRecord, чтобы я мог продолжать цепочку методов на него.

Я пытался выяснить, было ли у AREL какое-то решение для генерации простого запроса, который бы соответствовал вышеуказанному, но я застрял в тупике. Было бы достаточно просто циклически перебирать хэш параметров, чтобы учесть 2,3, 4 или X числа вишневых пиков, по которым вы могли бы фильтровать.

Это вообще возможно в AREL, рельсах или чем-то еще?

2 ответа

Следующее решение на самом деле является частью более крупной проблемы, но мне удалось заставить его работать, используя кусочки, которые вы мне дали:

def self.with_cherries(params={})
  # See also: http://stackru.com/questions/21689795/rails-arel-select-from-same-column-but-multiple-values
  result = all
  if (params.keys.length > 1)
    # filtering by 2 or more cherry picks
    result = result.joins(:cherries).where("cherry_picker_cherries.pickable_type = ?", self.name)

    # Setup the complicated joins
    params.each_with_index do |cherry_pick_and_value, index|
      result = result.joins("JOIN cherry_picker_cherries t#{index} USING(pickable_id)") unless index.zero?
    end

    my_query_string = ""
    params.values.each_with_index do |k, i|
      if i.zero?
        my_query_string << "cherry_picker_cherries.value = ?"
      else
        my_query_string << " AND t#{i}.value = ?"
      end
    end
    sanitized_string = self.sanitize_sql_array([my_query_string, params.values].flatten)
    result = result.where(sanitized_string).references(:cherries)
  else
    if params.present? && (params.keys.length == 1)
      # Only filtering by a single cherry pick
      result = result.with_cherry(params.first.first, params.first.last)
    end
  end
  result
end

Можете ли вы дать этому шанс?

CherryPicker::Cherry.joins("join cherry_picker_cherries t2 using(pickable_id)").where("cherry_picker_cherries.value = ? and t2.value = ?", 'orange', 'cherry')

Если это работает, вы можете перебрать фрукты, к которым хотите присоединиться, и сделать еще один joins с увеличенным именем переменной (t3, t4.. и т. д.), потому что SQL-запрос не будет выполнен, пока он не понадобится.

Вот как можно присоединиться к одной и той же таблице несколько раз:

arr = ['orange', 'cherry', 'apple']

query = CherryPicker::Cherry.joins("join cherry_picker_cherries t0 using(pickable_id)")

arr.drop(2).each_with_index do |e,i|
  query = query.joins("join cherry_picker_cherries t#{i+1} using(pickable_id)")
end

Вы можете сделать то же самое, чтобы создать свой wheres

Было бы здорово, если бы вы могли предложить правки, чтобы я мог улучшить этот пост, так как это действительно трудно проверить без ваших таблиц =)

Другие вопросы по тегам