Rails 4 LIKE查询-ActiveRecord添加引号


127

我正在尝试像这样的查询

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%'在最终查询中得到满意的结果?

Answers:


228

您的占位符将替换为字符串,并且操作不正确。

更换

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

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

6
这难道不容易受到SQL注入的攻击吗?我的意思是说,那些search绳子被消毒了吗?
jdscosta91 2014年

6
@ jdscosta91 ?该处将负责消毒
house9 2014年

7
在这种方法下,@ house9 %_内部的实例search将不会被清理。
巴里·凯利

8
使用“?”时 以这种方式在rails中将其转换为参数化查询。参数中的数据未清除(%),但无法从查询中更改上下文并将其转换为已处理的SQL语句。
大卫·赫尔策

50

不要使用conditionsRails 2 的语法,而使用Rails 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

注意:上面使用参数语法而不是?占位符:这两个都应生成相同的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名称-LIKE的postgres不区分大小写版本


这对Rails 5仍然有效吗?因为如果我将Movie.where("title ILIKE :s", s: search_string)它转换为SELECT 1 AS one FROM "movies" WHERE (title ILIKE 'test') LIMIT $1ActiveRecord(Rails 5.1.6)-请注意,ILIKE之后没有百分比符号)
sekmo

@sekmo-它应该起作用,百分比将进入search_string变量。我认为SELECT 1 AS one输出仅在Rails控制台中,或者您正在使用limit(1)?仅供参考:Rails 5.1.6存在安全问题,请改用5.1.6.2或5.1.7
house9

22

尽管字符串插值将起作用,但由于您的问题指定了rails 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

创建一个函数以使用属性列表动态地做到这一点应该真的很容易
cevaris 16/02/28

未经测试,尽管可能是这样:scope search_attributes,->(查询,属性){arel_attributes = attribute.map {| a | arel_table [a]} arel_queries = arel_attributes.map {| a | a.matches(query)}返回where(arel_queries.reduce {| res,q | res。或q})}
Pedro Rolo

8

ActiveRecord非常聪明,足以知道所引用的参数?是一个字符串,因此将其用单引号引起来。正如一篇文章所建议的那样,您可以使用Ruby字符串插值法在字符串上填充所需的%符号。但是,这可能会使您遭受SQL注入(这很糟糕)。我建议您使用SQL CONCAT()函数来准备字符串,如下所示:

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


我只是在应用程序中实现了它,效果很好。谢谢约翰。
Fuzzygroup

关于注射,没有,而且在任何情况下都没有区别。该字符串已插入到sql中,并且rails之前应该已经对其进行了验证(无论是否%附加/附加a )。它要么按预期工作,要么rails有一个严重的错误会影响这两种情况。
estani

5

尝试

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

有关更多信息,请参见有关AREL条件的文档


-1
.find(:all, where: "value LIKE product_%", params: { limit: 20, page: 1 })
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.