Islands in the byte stream

Technical notes by a software engineer

ActionArgsが素晴らしい件 #Rails

github.com

Railsのcontrollerで違和感があるのって

  • actionのinputに params というインスタンスメソッド経由でアクセスすること
    • しかも params はviewからアクセスできる!
  • actionのoutputが controller のインスタンス変数への代入であること
    • しかもそのインスタンス変数はviewからアクセスできる!

というところだと思うんですよ。

なぜなら我々は「メソッドの引数でinputを受け取りメソッドの戻り値をoutputとすべし」ということを是としてコードを書いてるわけじゃないですか。リーダブルコードを読むまでもなく、変数のスコープは狭ければ狭いほどメンテナンスしやすいリーダブルなコードだというベストプラクティスを正しいものとしてコードを書いているわけじゃないですか。

そういうベストプラクティスに真っ向から反しているのが現在のRailsのcontrollerのあり方なのです。controllerとviewで params から自由自在にパラメータを引き出して、特定のcontrollerのアクションがどういうパラメータを取りうるかさっぱりわからないということになりがちです。 この params のスコープの広さはまるでグローバル変数のようです。

ActionArgsは、リクエストパラメータのうち params でアクセスするパラメータをRubyのメソッドシグネチャで表現できるようにするgemです。

ActionArgsのもとでは、controllerはたとえばこんな感じになります:

class UsersController < ApplicationController
  def index(page: '1', per: '20')
    @users = User.page(page).per(per)
  end

  def show(id:)
    @user = User.find(id)
  end
end

#index が任意パラメータとしてpageper をとり、それらのデフォルト値がそれぞれ1と20であること、show が必須パラメータとして id をとるということが、メソッドのシグネチャをみるだけで一目でわかりますね。すばらしい。もっとも、 #create#update の場合はパラメータのデータ構造がネストするのでそれほど自明ではありませんが、それでもないよりはずっとマシです。スコープの広すぎる params を使わなくて済むのですから。

個人的にはActionArgsがRails組み込みでほしいですが、まずは誰もが使う標準的なgemにならないとなと思ってこのエントリを書きました。

実際の使い方は action_args/README を読むのがよいと思います。ただし、常にキーワード引数を使うべきです。READMEでも触れられていますが、非キーワード引数の場合デフォルト引数の扱いに制約があるからです。