Условия с переменными привязки и дополнительными параметрами
-
10-07-2019 - |
Вопрос
Допустим, у меня есть форма, в которой пользователи могут искать людей, чье имя начинается с определенной буквы. 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]} : {}) } }
Надеюсь, это поможет