Условия с переменными привязки и дополнительными параметрами

StackOverflow https://stackoverflow.com/questions/1642105

Вопрос

Допустим, у меня есть форма, в которой пользователи могут искать людей, чье имя начинается с определенной буквы. name строка, например, «Ми» найдет «Майка» и «Мигеля».Я бы, вероятно, создал такой оператор поиска:

find(:all, :conditions => ['name LIKE ?', "#{name}%"])

Допустим, в форме также есть два необязательных поля: hair_color и eye_color который можно использовать для дальнейшей фильтрации результатов.Если игнорировать часть имени запроса, оператор поиска для людей, которые могут принимать произвольное количество необязательных параметров, может выглядеть следующим образом:

find(:all, :conditions => { params[:person] })

Что для моих двух необязательных параметров будет вести себя как эквивалент этого:

find(:all, :conditions => { :hair_color => hair_color, :eye_color => eye_color })

Чего я не могу понять, так это как объединить эти два типа запросов, в которых обязательное поле «имя» применяется к приведенному выше условию «нравится», а необязательное поле hair_color и eye_color параметры (и, возможно, другие) могут быть добавлены для дальнейшей фильтрации результатов.

Я, конечно, могу создать для этого строку запроса, но я чувствую, что должен быть более элегантный «рельсовый путь».Как объединить обязательные параметры привязки с необязательными параметрами?

Это было полезно?

Решение

Это идеальное использование именованной области.

создайте именованную область в модели:

named_scope :with_name_like, lambda {|name|
  {:conditions => ['name LIKE ?', "#{name}%"]}
}

В этот момент вы можете позвонить

Model.with_name_like("Mi").find(:all, :conditions => params[:person])

И Rails объединит запросы за вас.

Редактировать:Код для Васима:

Если имя не является обязательным, вы можете либо исключить именованную область из цепочки методов с помощью условия if:

unless name.blank?
   Model.with_name_like("Mi").find(:all, :conditions => params[:person])
else
   Model.find(:all, :conditions => params[:person])
end

Или вы можете переопределить именованную область, чтобы сделать то же самое.

named_scope :with_name_like, lambda {|name|
  if name.blank?
    {}
  else
    {:conditions => ['name LIKE ?', "#{name}%"]}
  end
}

Обновлять

Вот версия последнего фрагмента кода для Rails 3:

scope :with_name_like, lambda {|name|
  if not name.blank?
    where('name LIKE ?', "#{name}%")
  end
}

Другие советы

Чтобы выполнить также запрос Waseem, но разрешить вместо nil пустое значение? (что очень плохо, если вы хотите использовать " @things = Thing.named_like (params [: name]) " напрямую)

named_scope :named_like, lambda do |*args| 
  if (name=args.first)
    {:conditions => ["name like ?",name]}
  else
    {}
  end
end

# or oneliner version:

named_scope :named_like, lambda{|*args| (name=args.first ? {:conditions => ["name like ?",name]} : {}) } }

Надеюсь, это поможет

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top