#Ransackで自前scope使う時に'1'や'0'を値として渡せない?
Railsアプリに簡単に検索機能を追加できるransackを使っています。
ここで一つの問題にぶつかってしまいました。
ぶつかった問題
検索値に1を設定するとArgumentError (wrong number of arguments (0 for 1))
が発生する。
(0、2、3、、、、なら発生せず)
やりたいこと
Viewからselectで選択したメニューの値(1,2,3,..)を受け取り、その値を検索値とし、自前のscopeをransack経由で使おうとしました。
以下はモデルとコントローラー抜粋。
:
scope :pathogen_eq, ->(pathogen) {joins(:test_results).merge(TestResult.where(pathogen: pathogen)).uniq}
:
def self.ransackable_scopes(auth_object = nil)
%i(pathogen_eq)
end
:
def index
@q = Report.ransack(params[:q])
:
end
何が起こっている?
エラーをキーワードに検索すると、RansackのIssueに次のようなものが見つかりました。
Wrong result and errors for join/group/having scope with certain values (0 and 1) #502
Issue502
- scopeに渡すときに、0と'0'をfalseに、1と'1'をtrueに変換しているので、値で渡せない
- 0と1は変換しないように修正(一旦Close)
- 今度はチェックボックスの場合に問題発生(ReOpen)
- その後修正のやり取りがあるけどテストが通らずOpenのまま
という状況のようです。
ransackのソースを見ると、確かに0と1はboolean扱いになっていました。
module Ransack
module Constants
:
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
BOOLEAN_VALUES = (TRUE_VALUES + FALSE_VALUES).freeze
:
対応
全てをRansackに任せる必要はなかったので、値渡しのところは自前でscopeを呼ぶようにしました。
:
scope :pathogen_eq, ->(pathogen) {joins(:test_results).merge(TestResult.where(pathogen: pathogen)).uniq}
:
def index
@q = Report.ransack(params[:q])
reports = @q.result
if params[:q].present? && params[:q][:pathogen_eq].present?
reports = reports.pathogen_eq(params[:q][:pathogen_eq])
end
:
end
値によってはテストも通ってしまうので、使う人は気を付けた方が良いです。
(修正PullRequestまでは手が出せていません、、、)