0

我有一个表格,用户可以使用许多不同类型的组合以多种方式进行过滤。对于我从用户那里获得的所有输入数据,从 SQL 中转义用户数据对我来说很重要,这会导致我现在遇到的问题。我有两个数组,它们是根据发送给动作的参数动态构建的,一个数组包含 SQL 子句,另一个包含要与其各自的原因配对的值……例如……

def results

  sql_clauses = Array.new
  sql_args = Array.new

  unless params[:elapsed_time].nil?
    sql_clauses << "elapsed_time = ?"
    sql_args << params[:elaped_time] 
  end
  unless params[:age_greater_than].nil?
    sql_clauses << "age > ?"
    sql_args << params[:age_greater_than]
  end
  .....
  @results = Model.where(sql_clauses.join(" and "), sql_args.join(", "))

end

现在这将 sql_clauses 数组发送到 where 方法没有问题。但是它在第二个参数上爆炸了,因为它返回一个字符串,并且它期望单个变量与每个“?”相对应。出现在 sql_clauses 数组中的字段。我已经尝试了 KandadaBoggu 在Comine arrays of conditions in rails上提供的解决方案。虽然这些选项都不适合我,但这可能是因为我使用的是 2 个数组而不是 1 个。

有人知道我的问题的解决方案吗?

4

2 回答 2

5

在 Rails 3 中无需使用字符串来构建动态查询。ActiveRecord 方法(如 select、where、order、limit 等)返回 ActiveRecord::Relation 对象,这些对象可以链接起来而不会触发多个数据库调用:

cars = Car.where(:colour => 'black') # No database queries are generated here.
rich_ppls_cars = cars.order('cars.price DESC').limit(10) # Still no db queries.

.all当我们调用、.first.last.eachActiveRecord::Relation 对象时,将查询数据库。

示例代码

假设您正在查询具有以下列的模型:

  • 姓名
  • elapsed_time
  • 年龄

你有一个看起来像这样的 params 哈希:

{ :elapsed_time => 34, :age_greater_than => 14, :max_rows => 20 }

您的控制器操作可能如下所示:

def results
    query = ModelName.select([:name, :elapsed_time, :age])
    query = query.where(:elapsed_time => params[:elapsed_time])  if params[:elapsed_time].present?
    query = query.where('age > ?', params[:age_greater_than])  if params[:age_greater_then].present?
    query = query.limit(params[:max_rows])  if params[:max_rows].present?
    @dynamic_query = query
end

请注意,我正在使用.present?. 这可以防止我们将 params 哈希中的空白字符串误解为有效数据。

参考资料

于 2012-05-27T19:08:52.383 回答
1

尝试这样的事情:

def results
  sql_clauses = []
  sql_clauses << "elapsed_time = :elapsed_time" if params[:elapsed_time]
  sql_clauses << "age > :age_greater_than" if params[:age_greater_than]
  .....
  @results = Model.where(sql_clauses.join(" and "), params)
end

where支持各种不同的构建条件语法。

如果您有很多可能的文件要包含,我会以某种方式制作一个映射字典,如下所示:

map = {
   :elapsed_time => "elapsed_time =",
   :age_greater_than => "age >"
}

然后遍历params键并构建子句(如果它们存在于map.

于 2012-05-24T20:57:04.433 回答