QA@IT

StrongParametersでaction_argsを使用した際、デフォルト値にnil以外が設定出来ない

3886 PV

StrongParametersでaction_argsを使用した場合、アクションの引数に指定したパラメータが存在しないとエラーになり、エラーを回避する為にはデフォルト値を設定すれば良いようなのですが、このデフォルト値にnil以外の値を設定しても全てnilになってしまうという事象になっています。

  # the `page` parameter is optional
  def index(page = nil)
    p page
  end

params[:page]が無ければpage==nil

  # the `page` parameter is optional
  def index(page = 10)
    p page
  end

params[:page]が無いとpage==nilとなる

何か使い方が間違っているのでしょうか?

環境は下記の通りです。

ruby -v
----------
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin12.2.1]
----------
rails -v
----------
Rails 4.0.0.rc1
----------

回答

はい。ご指摘の問題は既知のものではあったのですが、残念ながら実装の都合上どうしてもそうなってしまうので、つまりaction_argsの「仕様」です、というしかないところでした (gosub 言いわけ)。

が、よく考えてみたらRuby 2.0の素敵な新機能「キーワード引数」を使えばうまくいきそうな気がしたので、ちょっと実装してみました。 https://github.com/asakusarb/action_args/commit/04e6c8712a860c05052fd82eb4ea16ade2763293

もしよかったらこのGHの先っちょをbundleしてみて試してみていただけますか?


言いわけ: なぜメソッド仮引数にnil以外を設定しててもnilが渡されてしまうのか

そもそも今のRubyの仕様では、以下のように複数の省略可能なパラメーターが宣言されたメソッドに対して、arg1のデフォルト値を生かしながらarg2を渡すことができません。

def meth(arg1 = 1, arg2 = 2)
  ...
end

このメソッドをmeth(nil, 3)のように呼ぶとarg1: nil, arg2: 2になってしまうし、かと言ってmeth(3)ならarg1: 3, arg2: 2とみなされてしまいます。

action_argsでは、method宣言のparametersを見て、仮引数名をそのままキーにしてparamsから値を引っ張ってきてアクションメソッドの呼び出しに渡しているのですが、上記のケースを含む色んな形のメソッド定義に対応するために、ユーザーから値が渡されていようがいなかろうが、全ての省略可能パラメーターにnilを充填してやって呼び出しています。
たとえば、上記のアクションに対して飛んできたparamsが{arg2: 3}だった場合に、arg1: nilを補充して呼び出してやらないと、arg2のはずの値がarg1に渡されてしまう可能性があるからです。

この問題に完璧に対処するためには、メソッド呼び出しのパラメーターを定義された順序だけじゃなくて名前をキーにしたHashか何かで渡すことができれば良いんですけどね。あ、あれ?それってもしかして「キーワード引数」そのもの?
return。

編集 履歴 (0)
  • ありがとうございます。「gem 'action_args', github: 'asakusarb/action_args'」でインストールしたもので、「def index(page: "10")」のように指定して希望通りの挙動になりましたー。 -

1.9では正常なので2.0の不具合か仕様変更かと
http://ideone.com/ReGur5

編集 履歴 (0)
  • 回答ありがとうございます。確かにaction_args関係なくRuby2.0での引数のデフォルト値の設定の問題のようですね。。 -
  • 今、Ruby2.0のirbで試してみた限りでは、通常のdef method(args="TEST") 〜 endなどの定義でmedhod()などで呼んだ場合は正常にデフォルト値が設定されるので、やはりaction_args側の問題かも知れません。 -
  • http://ideone.com/ReGur5 を少し変更してみたがなんか index(nil)で呼ばれてる予感 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。