0

我正在努力寻找对动态方法进行元编程的最佳方法,我将根据条件限制结果......例如:

class Timeslip < ActiveRecord::Base

    def self.by_car_trans(car, trans)
        joins(:car)
        .where("cars.trans IN (?) and cars.year IN (?) and cars.model ILIKE ?", trans, 1993..2002, car)
        .order('et1320')
    end

end

假设我没有传入我的参数,而是传入一个条件数组,其中键是字段名,值是字段值。例如,我会做这样的事情:

我会传入 [["field", "value", "operator"],["field", "value", "operator"]]

def self.using_conditions(conditions)
    joins(:car)
    conditions.each do |key, value|
      where("cars.#{key} #{operator} ?", value)
    end
end

但是,这不起作用,而且不是很灵活......我希望能够检测该值是否是一个数组,并使用 IN () 而不是 =,也许能够使用 ILIKE 来区分大小写条件也...

任何建议表示赞赏。我的主要目标是建立一个“列表”模型,用户可以在其中动态构建他们的条件,然后保存该列表以供将来使用。该列表将根据关联的汽车表过滤时间片模型......也许有更简单的方法来解决这个问题?

4

2 回答 2

2

首先,您可能会对Squeel gem 感兴趣。

除此之外,arel_table用于 IN 或 LIKE 谓词:

 joins( :car ).where( Car.arel_table[key].in      values )
 joins( :car ).where( Car.arel_table[key].matches value  )

您可以检测值的类型以选择适当的谓词(不是很好的 OO,但仍然):

 column    = Car.arel_table[key]
 predicate = value.respond_to?( :to_str ) ? :in : :matches # or any logic you want

 joins( :car ).where( column.send predicate, value )

您可以根据需要链接任意数量的链接:

 conditions.each do |(key, value, predicate)|
   scope = scope.where( Car.arel_table[key].send predicate, value )
 end
 return scope
于 2013-01-30T20:33:29.593 回答
0

那么,您想要最终用户可以在运行时指定的动态查询(并且可以存储和检索以供以后使用)?

我认为你在正确的轨道上。唯一的细节是您如何建模和存储您的标准。我不明白为什么以下内容不起作用:

def self.using_conditions(conditions)
  joins(:car)
  crit = conditions.each_with_object({}) {|(field, op, value), m|
    m["#{field} #{op} ?"] = value
  }
  where crit.keys.join(' AND '), *crit.values
end

CAVEAT上面的代码不安全的并且容易被 SQL 注入。

此外,没有简单的方法来指定ANDvsOR条件。最后,simple"#{field} #{op} ?", value大部分只适用于数字字段和二元运算符。

但这说明这种方法是可行的,只是还有很大的改进空间。

于 2013-01-31T05:02:25.317 回答