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_tableIN または 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

警告上記のコードはそのままでは安全ではなく、SQL インジェクションを起こしやすいです。

また、ANDvsOR条件を指定する簡単な方法はありません。最後に、simple"#{field} #{op} ?", valueはほとんどの場合、数値フィールドと二項演算子に対してのみ機能します。

しかし、これは、改善の余地がたくさんあるだけで、このアプローチが機能することを示しています。

于 2013-01-31T05:02:25.317 に答える