2013-09-30 4 views
96

Я пытаюсь сделать как запрос типа такRails 4 LIKE запроса - ActiveRecord добавляет кавычки

def self.search(search, page = 1) 
    paginate :per_page => 5, :page => page, 
    :conditions => ["name LIKE '%?%' OR postal_code like '%?%'", search, search], order => 'name' 
end 

Но когда он запускается что-то добавляет кавычки, которые вызывают заявление SQL, чтобы выйти, как так

SELECT COUNT(*) 
FROM "schools" 
WHERE (name LIKE '%'havard'%' OR postal_code like '%'havard'%')): 

Таким образом, вы можете видеть мою проблему. Я использую Rails 4 и Postgres 9, оба из которых я никогда не использовал, поэтому не уверен, что это и вещь activerecord или, возможно, вещь postgres.

Как я могу установить это, поэтому у меня есть '%my_search%' в конце запроса?

ответ

179

Ваш заменитель заменен на строку, и вы не обрабатываете ее правильно.

Заменить

"name LIKE '%?%' OR postal_code LIKE '%?%'", search, search 

с

"name LIKE ? OR postal_code LIKE ?", "%#{search}%", "%#{search}%" 
+2

не это уязвимы для SQL инъекций? Я имею в виду, что эти «поисковые» строки дезинфицируются? – jdscosta91

+3

@ jdscosta91 '?' В том, где позаботится о дезинфекции – house9

+6

@ home9 экземпляры '%' и '_' внутри' search' не будут дезинфицированы под этим подходом. –

4

Попробуйте

def self.search(search, page = 1) 
    paginate :per_page => 5, :page => page, 
     :conditions => ["name LIKE ? OR postal_code like ?", "%#{search}%","%#{search}%"], order => 'name' 
    end 

См docs об условиях AREL для получения дополнительной информации.

40

Вместо того чтобы использовать conditions синтаксис из Rails 2, использует в рельсах 4 where метода вместо того, чтобы:

def self.search(search, page = 1) 
    wildcard_search = "%#{search}%" 

    where("name ILIKE :search OR postal_code LIKE :search", search: wildcard_search) 
    .page(page) 
    .per_page(5) 
end 

Примечания: выше использует синтаксис параметра вместо? placeholder: они должны генерировать тот же sql.

def self.search(search, page = 1) 
    wildcard_search = "%#{search}%" 

    where("name ILIKE ? OR postal_code LIKE ?", wildcard_search, wildcard_search) 
    .page(page) 
    .per_page(5) 
end 

Примечание: с помощью ILIKE для имени - Postgres регистронезависимы версия LIKE

20

Хотя строка интерполяции будет работать, так как ваш вопрос задает рельсы 4, вы можете использовать Arel для этого и сохранить вашу базу данных приложения агностик.

def self.search(query, page=1) 
    query = "%#{query}%" 
    name_match = arel_table[:name].matches(query) 
    postal_match = arel_table[:postal_code].matches(query) 
    where(name_match.or(postal_match)).page(page).per_page(5) 
end 
+0

Должно быть очень просто создать func, чтобы сделать это динамически со списком атрибутов – cevaris

+0

Untested, хотя это может быть что-то вроде этого: scope search_attributes, -> (query, attributes) { arel_attributes = attributes.map {| a | arel_table [a]} arel_queries = arel_attributes.map {| a | a.matches (query)} return where (arel_queries.reduce {| res, q | res.or q}) } –

-1
.find(:all, where: "value LIKE product_%", params: { limit: 20, page: 1 }) 
3

ActiveRecord достаточно умен, чтобы знать, что параметр ссылается ? является строкой, и поэтому он заключает ее в одинарные кавычки. Вы, , могли бы, поскольку одно сообщение предлагает использовать интерполяцию строк Ruby для заполнения строки с обязательными символами %. Однако это может привести к SQL-инъекции (что плохо). Я хотел бы предложить вам использовать функцию SQL CONCAT() подготовить строку следующим образом:

"name LIKE CONCAT('%',?,'%') OR postal_code LIKE CONCAT('%',?,'%')", search, search)

+0

Я только что реализовал это в приложении, и он отлично поработал. Спасибо, Джон. – fuzzygroup

Смежные вопросы