LoginSignup
2
2

More than 5 years have passed since last update.

ActiveAdminで自作scopeを使ったfilterに'1'を渡すとエラーになる

Last updated at Posted at 2017-08-30

現象

ActiveAdminにて、以下のようなコードで自作scopeを利用したfilterを使うと、検索値が'1'のときに ArgumentError (wrong number of arguments (0 for 1)) が発生する。

model/product.rb
class Product < ActiveRecord::Base
  ...

  # custom scope
  scope :original_scope, -> (product_id) {
    product = Product.find(product_id)
    # do something
  end

  def self.ransackable_scopes(_auth_object = nil)
    %i(original_scope)
  end

  ...
end
app/product_admin/product.rb
ActiveAdmin.register Product, namespace: :product_admin do
  ...

  filter :original_scope, as: :select, collection: -> { Product.all }

  ...
end

原因調査

調べてみると、どうやらscopeに渡すときに、0と'0'をfalseに、1と'1'をtrueに変換しているので、値で渡せないようです。

Ransackで自前scope使う時に'1'や'0'を値として渡せない?

関連するIssueを見るとCloseになっているのですが、バージョンの問題なのか私の環境ではエラーのままでした。

Wrong result and errors for join/group/having scope with certain values (0 and 1) #502

対処

案1:可変長引数を使う

可変長引数で受けるとvalue=[]になるので、無理やり書き換える。
今回のケースではidを渡す用途のため、0は無視する。

model/product.rb
class Product < ActiveRecord::Base
  ...

  # custom scope
  scope :original_scope, -> (*product_id) {
    product_id = [1] if product_id == [] # hotfix
    product = Product.find(product_id[0])
    # do something
  end

  ...
end

かなり強引なやりかたで、汎用性も低そうなので、できれば避けたい。

案2:代わりになる引数を使う

今回のケースでは、引数で渡した数値(ID)を使ってProductの検索をするため、数値を使わずに検索できる方法を利用した。

model/product.rb
class Product < ActiveRecord::Base
  ...

  # custom scope
  scope :original_scope, -> (product_name) {
    product = Product.find_by(name: product_name)
    # do something
  end

  ...
end

この方法では当たり前かもしれないが、

  1. ユニークな値であること
  2. インデックスが張られていること

がないとレコードが複数件ヒットしたり、検索が遅かったりする。


もっとスマートな解決方法があれば、ぜひコメントをm(_ _)m

おわり

2
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2