简体   繁体   English

轨动态SQL查询

[英]rails dynamic where sql query

I have an object with a bunch of attributes that represent searchable model attributes, and I would like to dynamically create an sql query using only the attributes that are set. 我有一个带有一堆代表可搜索模型属性的属性的对象,我想仅使用设置的属性来动态创建sql查询。 I created the method below, but I believe it is susceptible to sql injection attacks. 我在下面创建了方法,但是我认为它容易受到sql注入攻击。 I did some research and read over the rails active record query interface guide, but it seems like the where condition always needs a statically defined string as the first parameter. 我进行了一些研究,并阅读了Rails活动记录查询界面指南,但似乎where条件始终需要静态定义的字符串作为第一个参数。 I also tried to find a way to sanitize the sql string produced by my method, but it doesn't seem like there is a good way to do that either. 我还试图找到一种方法来清理由我的方法生成的sql字符串,但是似乎也没有一种好的方法。

How can I do this better? 我该如何做得更好? Should I use a where condition or just somehow sanitize this sql string? 我应该使用where条件还是以某种方式清除此sql字符串? Thanks. 谢谢。

def query_string
  to_return = ""

  self.instance_values.symbolize_keys.each do |attr_name, attr_value|
    if defined?(attr_value) and !attr_value.blank?
      to_return << "#{attr_name} LIKE '%#{attr_value}%' and "
    end
  end
  to_return.chomp(" and ")
end

Your approach is a little off as you're trying to solve the wrong problem. 您尝试解决错误问题的方法有些偏离。 You're trying to build a string to hand to ActiveRecord so that it can build a query when you should simply be trying to build a query. 您正在尝试构建要传递给ActiveRecord的字符串,以便在您仅应尝试构建查询时就可以构建查询。

When you say something like: 当您说类似:

Model.where('a and b')

that's the same as saying: 就是说:

Model.where('a').where('b')

and you can say: 你可以说:

Model.where('c like ?', pattern)

instead of: 代替:

Model.where("c like '#{pattern}'")

Combining those two ideas with your self.instance_values you could get something like: 将这两个想法与您的self.instance_values结合起来,您将得到如下结果:

def query
  self.instance_values.select { |_, v| v.present? }.inject(YourModel) do |q, (name, value)|
    q.where("#{name} like ?", "%#{value}%")
  end
end

or even: 甚至:

def query
  empties      = ->(_, v) { v.blank? }
  add_to_query = ->(q, (n, v)) { q.where("#{n} like ?", "%#{v}%") }
  instance_values.reject(&empties)
                 .inject(YourModel, &add_to_query)
end

Those assume that you've properly whitelisted all your instance variables. 那些假设您已经正确地将所有实例变量列入了白名单。 If you haven't then you should. 如果还没有,那么应该。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM