Поиск в Rails с несколькими условиями (если значения не пусты) - PullRequest
1 голос
/ 16 февраля 2012

Допустим, у меня есть модель Book с полем word_count, среди потенциально многих других подобных полей.

Какой хороший способ объединить условия в «расширенном поиске» базы данных?В приведенном выше примере у меня была бы форма поиска с полями для "word count between ___ and ___".Если пользователь заполняет первое поле, я хочу вернуть все книги с количеством слов, превышающим это значение;Аналогичным образом, если пользователь заполняет второе поле, я хочу вернуть все книги с количеством слов меньше этого значения.Если оба значения заполнены, то я хочу вернуть количество слов в этом диапазоне.

Очевидно, что если я сделаю

Book.where(:word_count => <first value>..<second value>)

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

Извините, если этот вопрос задавался ранее, но поиск по сайту не дал результатовникаких полезных результатов пока нет.

Ответы [ 3 ]

1 голос
/ 16 февраля 2012

Как насчет чего-то вроде:

@books = Book
@books = @books.where("word_count >= ?", values[0]) if values[0].present?
@books = @books.where("word_count <= ?", values[1]) if values[1].present?

ActiveRecord будет связывать предложения where

Единственная проблема состоит в том, что если values ​​[0] && values ​​[1], запрос не будет ничего возвращатьесли значения [0] больше значений [1].

1 голос
/ 16 февраля 2012

Для нашего расширенного поиска мы создаем объект фильтра, который инкапсулирует запросы activerecord в простые методы. Первоначально он был основан на этом сообщении Thoughtbot

Книжный фильтр может выглядеть примерно так:

class BookFilter
  def initialize
    @relation = Book.scoped
  end

  def restrict(r)
    minimum_word_count!(r[:first]) if r[:first].present?
    maximum_word_count!(r[:second]) if r[:second].present?
    recent! if r.try(:[], :recent) == '1'
    @relation
  end

  protected

  def recent!
    where('created_at > ? ', 1.week.ago)
  end

  def minimum_word_count!(count)
    where('word_count >= ? ', count)
  end

  def maximum_word_count!(count)
    where('word_count <= ?', count)
  end

  def where(*a)
    @relation = @relation.where(*a)
  end
end

#to use
books = BookFilter.new.restrict(params)
0 голосов
/ 16 февраля 2012

Посмотрите на камень Ransack , который является преемником камня meta_search , который, кажется, все еще содержит лучшую документацию.

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

scope = Book
scope = scope.where("word_count >= ?", params[:first]) if params[:first]
scope = scope.where("word_count <= ?", params[:last])  if params[:last]

Но на самом деле нет необходимости проводить собственный поиск, есть множество готовых решений, как в приведенных выше гемах..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...