Один или несколько параметров в модели находят условия с помощью Ruby on Rails - PullRequest
4 голосов
/ 02 ноября 2009

Скажем, у меня есть модель 'Car' и контроллер 'cars', а также метод 'display'.

У меня есть несколько атрибутов, таких как:

in_production, year, make

Я могу легко сделать что-то подобное, чтобы найти автомобили, которые соответствуют всем переданным параметрам:

def display
  @cars = Car.find(:all, :conditions => { :in_production => #{params[:in_production]}, :year => #{params[:year]}, :make => #{params[:make]} })`
end

Итак, я делаю кодирование жестких ссылок в меню, поэтому, если я хочу найти все автомобили Nissan 2009 года выпуска, я передам эти значения в качестве параметров в моей ссылке.

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

Есть идеи?

Ответы [ 4 ]

10 голосов
/ 02 ноября 2009

Прежде всего, используя

:conditions => "in_production = '#{params[:in_production]}' AND year = '#{params[:year]}' AND make = '#{params[:make]}'"

уязвим для внедрения SQL. Вы должны экранировать предоставленные пользователем параметры, прежде чем использовать их в условиях базы данных.

Нечто подобное должно позволить вам добавлять условия более динамично в зависимости от того, существуют параметры или нет. Я не проверял это, поэтому я могу редактировать это в ближайшее время ...

def display
  conditions = []
  conditions << [ "in_production = ?", params[:in_production] ] if params[:in_production].present?
  conditions << [ "year = ?", params[:year] ] if params[:year].present?
  conditions << [ "make = ?", params[:make] ] if params[:make].present?
  @cars = Car.all(:conditions => conditions )
end
4 голосов
/ 02 ноября 2009

Конечно, избегайте параметров и убедитесь, что вы запрашиваете только те поля, которые хотите открыть. Кроме того, вы можете использовать то, что встроено в Rails:

Car.find_all_by_in_production_and_year_and_make(in_production, year, make)

Выполнение условий вручную может позволить применить дополнительную логику (поиск по году, только если год находится между x и y и т. Д.). Использование искателей рельсов (которые, в свою очередь, используют method_missing) обеспечивает чистоту и гибкость API без необходимости смотреть на условия прямого SQL.

Вы можете создать метод поиска Car #, который принимает весь хэш параметров в качестве входных данных, где параметры очищаются и удаляются из неэкспонированных полей, и создавать вызов метода Car # find_all_by *, используя сами имена параметров. Добавление новых условий для поиска будет таким же простым, как и передача их в параметрах.

1 голос
/ 23 июля 2010

Я использую SmartTuple для подобных вещей. Простой, мощный, разработанный специально для этой задачи.

@cars = Car.all(:conditions => (SmartTuple.new(" AND ") + 
  ({:in_production => params[:in_production]} if params[:in_production].present?) +
  ({:year => params[:year]} if params[:year].present?) +
  ({:make => params[:make]} if params[:make].present?)
).compile)

или

@cars = Car.all(:conditions => [SmartTuple.new(" AND "),
  ({:in_production => params[:in_production]} if params[:in_production].present?),
  ({:year => params[:year]} if params[:year].present?),
  ({:make => params[:make]} if params[:make].present?),
].sum.compile)

или

keys = [:in_production, :year, :make]
@cars = Car.all(:conditions => (SmartTuple.new(" AND ").add_each(keys) do |k|
  {k => params[k]} if params[k].present?
end).compile)

Выберите тот, который вам нравится больше всего. :)

1 голос
/ 02 ноября 2009

Вы можете проверить searchlogic. Он использует какой-то метод, пропускающий магию, для создания named_scopes, которые будут делать то, что вы хотите.

http://github.com/binarylogic/searchlogic

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