如何在 Arel 和 Rails 中进行 LIKE 查询?
Posted
技术标签:
【中文标题】如何在 Arel 和 Rails 中进行 LIKE 查询?【英文标题】:How to do a LIKE query in Arel and Rails? 【发布时间】:2011-05-24 18:05:56 【问题描述】:我想做这样的事情:
SELECT * FROM USER WHERE NAME LIKE '%Smith%';
我在 Arel 的尝试:
# params[:query] = 'Smith'
User.where("name like '%?%'", params[:query]).to_sql
然而,这变成了:
SELECT * FROM USER WHERE NAME LIKE '%'Smith'%';
Arel 正确地包装了查询字符串 'Smith',但是因为这是一个 LIKE 语句,所以它不起作用。
如何在 Arel 中进行 LIKE 查询?
附:奖励——我实际上是在尝试扫描表上的两个字段,名称和描述,以查看查询是否有任何匹配项。这将如何运作?
【问题讨论】:
我更新了奖励的 arel 答案。 【参考方案1】:不要忘记转义用户输入。
你可以使用ActiveRecord::Base.sanitize_sql_like(w)
query = "%#ActiveRecord::Base.sanitize_sql_like(params[:query])%"
matcher = User.arel_table[:name].matches(query)
User.where(matcher)
您可以在models/user.rb
中简化
def self.name_like(word)
where(arel_table[:name].matches("%#sanitize_sql_like(word)%"))
end
【讨论】:
【参考方案2】:试试
User.where("name like ?", "%#params[:query]%").to_sql
PS。
q = "%#params[:query]%"
User.where("name like ? or description like ?", q, q).to_sql
已经很久了,但是@cgg5207 添加了一个修改(如果您要搜索长名称或多个长名称参数,或者您懒得输入,这将非常有用)
q = "%#params[:query]%"
User.where("name like :q or description like :q", :q => q).to_sql
或
User.where("name like :q or description like :q", :q => "%#params[:query]%").to_sql
【讨论】:
Rails 怎么知道不要在替换字符串中转义%
?似乎如果您只想要一个单面通配符,则没有什么可以阻止用户提交一个在两端包含 %
的查询值(我知道在实践中,Rails 会阻止 %
出现在查询字符串中,但似乎应该在 ActiveRecord 级别对此进行保护)。
这不是容易受到 SQL 注入攻击吗?
@Behrang no 8) User.where("name like %#params[:query]% or description like%#params[:query]%").to_sql 将易受攻击,但是,在我展示的格式中,Rails 转义了 params[:query]
抱歉跑题了。我有方法to_sql
或arel manager的sql git,如何在db上执行sql?
Model.where(to_sql_result)【参考方案3】:
这是您在 arel 中执行类似查询的方式:
users = User.arel_table
User.where(users[:name].matches("%#user_name%"))
PS:
users = User.arel_table
query_string = "%#params[query]%"
param_matches_string = ->(param)
users[param].matches(query_string)
User.where(param_matches_string.(:name)\
.or(param_matches_string.(:description)))
【讨论】:
与使用where("name like ?", ...)
不同,这种方法在不同数据库之间更便携。例如,这将导致在针对 Postgres 数据库的查询中使用 ILIKE
。
这是否可以防止 SQL 注入?
这并不能完全防止 SQL 注入。尝试将 user_name 设置为“%”。查询将返回匹配项
我尝试直接使用参数进行 sql 注入,User.where(users[:name].matches("%#params[:user_name]%"))
,我尝试了TRUNCATE users;
和其他此类查询,但 sql 端没有任何反应。对我来说看起来很安全。
使用.gsub(/[%_]/, '\\\\\0')
转义mysql通配符。【参考方案4】:
Reuben Mallaby 的答案可以进一步缩短以使用参数绑定:
User.where("name like :kw or description like :kw", :kw=>"%#params[:query]%").to_sql
【讨论】:
以上是关于如何在 Arel 和 Rails 中进行 LIKE 查询?的主要内容,如果未能解决你的问题,请参考以下文章
如何解决 Arel 与 Hartl Rails 教程(第 2 章)不兼容的问题?
Rails/Arel:选择所有记录作为 ActiveRecord::Relation