Rails Поиск с дополнительными параметрами? - PullRequest
23 голосов
/ 18 декабря 2010

Как мне выполнить поиск в базе данных, когда поиск может предоставить множество необязательных параметров, таких как ID, Zip, City и State? Они могут иметь значения или быть полностью пустыми. Как бы я сделал запрос рельсов, как это?

Ответы [ 3 ]

32 голосов
/ 19 декабря 2010

Обычный совет - перенести логику в модель и поддерживать контроллер как можно более скудным. Существуют разные подходы к методу фильтрации, первый:

class Record < ActiveRecord::Base
  def self.filter(attributes)
    attributes.select { |k, v| v.present? }.reduce(all) do |scope, (key, value)|
      case key.to_sym
      when :id, :zip # direct search
        scope.where(key => value)
      when :city, :state # regexp search
        scope.where(["#{key} ILIKE ?", "%#{value}%"])
      when :order # order=field-(ASC|DESC)
        attribute, order = value.split("-") 
        scope.order("#{self.table_name}.#{attribute} #{order}")
      else # unknown key (do nothing or raise error, as you prefer to)
        scope
      end 
    end  
  end
end

Второй подход, написать голый filter, который использует только существующие области:

class Record < ActiveRecord::Base
  SUPPORTED_FILTERS = [:id, :city, ...]
  scope :id, ->(value) { where(id: value) }
  scope :city, ->(value) { where(city: "%#{value}%") }
  ...

  def self.filter(attributes)
    attributes.slice(*SUPPORTED_FILTERS).reduce(all) do |scope, (key, value)|
      value.present? ? scope.send(key, value) : scope
    end  
  end
end

Для Rails 5, который теперь использует ActionController :: Parameters, синтаксис для метода фильтра:

def self.filter(attributes)
  attributes.permit(SUPPORTED_FILTERS).to_hash.reduce(all) do |scope, (key, value)|
    value.present? ? scope.send(key, value) : scope
  end  
end

Модели можно вызывать из любого места в вашем приложении, поэтому их можно повторно использовать и проще тестировать. Теперь контроллер выглядит так просто:

class RecordsController < ApplicationController::Base
  respond_to :html, :xml

  def index
    @records = Record.filter(params)
  end
end
17 голосов
/ 18 декабря 2010

Вы можете создать запрос:

conditions = {}
conditions[:city] = city unless city.blank?
conditions[:zip] = zip unless zip.blank?
conditions[:state] = state unless state.blank?
Address.find(:all, :conditions => conditions)
0 голосов
/ 27 февраля 2011

http://metautonomo.us/projects/metasearch/ - это то, что вам нужно.

= text_field_tag 'search[city_like]', ''
= text_field_tag 'search[zip_equals]', ''
= text_field_tag 'search[state_equals]', ''

А потом просто

Record.search(params[:search])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...