まとめ
下記の ransacker とパラメータの組み合わせで (model.column_A <= model.column_B) = TRUE
が条件に追加されます。同じテーブルのカラム同士の比較を条件に加えることができます。
ransacker "compare", args: %i[parent ransacker_args] do |parent, args|
columns = args.values
Arel::Nodes::Grouping.new(
Arel::Nodes::InfixOperation.new(
'<=',
parent.table[columns[0].to_sym], parent.table[columns[1].to_sym]
)
)
end
'q' => {
'c' => {
'0' => {
'a' => {'0' => {'name' => 'compare',
'ransacker_args' => {
'0' => 'column_A',
'1' => 'column_B'
}
}
},
'p' => 'true',
'v' => {'0' => {'value' => 1}
}
}
}
}
v3.2.1 で動作することを確認してます。
https://github.com/activerecord-hackery/ransack/releases/tag/v3.2.1
v4.0.0 以降は未検証。
解説
ransacker
ransacker "compare", args: %i[parent ransacker_args] do |parent, args|
columns = args.values
Arel::Nodes::Grouping.new(
Arel::Nodes::InfixOperation.new(
'<=',
parent.table[columns[0].to_sym], parent.table[columns[1].to_sym]
)
)
end
ransacker で追加の ransack 用のメソッドを用意してあげます。
args: %i[parent ransacker_args]
で ransacker_args
を使えるようにして、ブロック引数にも args
を書いて、ブロックの中で使えるようにします。
Arel::Nodes::Grouping
は ()
に引数の結果を収めてくれます。これを書かないと SQL の式が成り立たないです。
Arel::Nodes::InfixOperation
は第一引数に演算子をとって、第二引数と第三引数を演算する式を返します。
この ransacker は (model.column_A <= model.column_B)
という式を作ります。
パラメータ
'q' => {
'c' => {
'0' => {
'a' => {'0' => {'name' => 'compare',
'ransacker_args' => {
'0' => 'column_A',
'1' => 'column_B'
}
}
},
'p' => 'true',
'v' => {'0' => {'value' => 1}
}
}
}
}
Advanced Mode を使います。
比較するだけなので p や v は不要に思えますが、a p v の3つが揃わないと ransack が条件として追加してくれないようなので p や v も書きます。
a の name には素直に追加した ransacker のメソッド名を書きます。
ransacker_args には比較したいカラムを書きます。
p は true、value は 1 にします。でも、value は何でもいいです。
考察
ransacker_args を使わないと、比較するカラムの組み合わせの数だけ ransacker を書かないといけなくなりますが、このように ransacker_args を使えばコンパクトに書けます。
便利ですね。