概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Do you use form objects in your Rails apps? - Write it simple
- 原文公開日: 2020/04/04
- 著者: Juan Manuel Ramallo
日本語タイトルは内容に即したものにしました。
Rails: シンプルなForm Object gem「yaaf」(翻訳)
RailsアプリでForm Objectパターンを使いやすくするyaafというgemをご紹介します。
Form Objectでつらかった点(yaafがなかった頃)
Form ObjectパターンはRailsアプリで広く用いられており、私たちは今もプロジェクトごとに異なる方法でForm Objectを書く傾向があります。
そうしたForm Objectはほとんどの場合、同一のアプリの中ですらインターフェイスが揃っていません。
また私たちは、Form Objectで発生したエラーが表示されるよう、バリデーションを(それぞれモデルとForm Objectで)2回書いてしまう傾向もあります。
ところで、こうした社内Form Objectのほとんどはデータベーストランザクションをうまく利用できていると思います。しかしそれらが、何か問題が起きたときにエラーをraiseすることが期待される!
付きメソッドをコントローラに提供できていることはめったにないことについては賭けてもよいです。
ビジネスロジックは、アプリの「コントローラ」「モデル」「ヘルパー」のあらゆる場所に存在します(中にはRailsのイニシャライザに仕込まれているというつらいシナリオもあります)が、それで正しいのでしょうか?私たちは、(メール送信やレコード更新や外部サービス呼び出しなどで)何かオブジェクトを作成するときにビジネスロジックの追加が必要だと繰り返し気付かされます。コントローラがビジネスロジックの置き場としてふさわしくないことは私たちも既に知っていますし、かといってモデルに置くのも単一責任の原則(SRP)に違反するのでよろしくないことも知っています。しまいには、Service Objectをいくつもこしらえてはビジネスロジックをゴミ箱のようにそこに放り込むのがオチです。
そうせずにやる方法は、ある
yaaf gemを使えば以上の問題を楽に解決できます。これについて説明させてください。
インターフェイスを統一したい: yaafはsave
の利用を促進し、皆さまがご存知のように、フォームのデータをモデルに「保存」するためにsave
を実行します。
コンテキストに沿うバリデーションだけを実行したい: 自分のForm Objectにバリデーションを書いて、データが所属する場所でデータ一貫性バリデーションを維持しましょう。データが所属する場所というとService Objectのことでしょうか?まさか、モデルのことです。yaaf gemは、モデルのあらゆるエラーのコレクションをForm Objectエラーのコレクションに昇格させ、ビューでそれらのエラーを表示できるようにしてくれます。
では、あるForm Objectでsave
が行われなかった場合にエラーをraiseする必要があるときはどうすればよいでしょうか?既にお気づきかと思いますが、!
付きのsave!
メソッドをお使いください。yaafではsave!
が定義済みなので、Active Recordモデルと同様にエラーをraiseします。もちろん、モデルでsave
に失敗した場合はデータベースロールバックもトリガーされます。つまりsave
とsave!
のどちらも使えるのです。
オブジェクト作成に関連するビジネスロジックの置き場に迷う: Form Objectがその置き場所です。yaaf gemを用いることで、モデルでコールバックが動くときと同じ方法でコールバックを利用できるようになります。たとえば、フォームを送信して永続化した後にメールを送信したい場合なら、after_commit
コールバックがそれでしょう。詳しくはyaaf gemのREADMEをご覧ください。
Form Objectの標準化
yaaf gemを用いることで、プロジェクトのproduction用コードにわたってForm Objectの定義を標準化できるようになります。
yaaf gemを使わない理由があるとすれば
すべての責務をどうしてもコントローラーで扱いたいのであればご自由にどうぞ。この場合yaaf gemの出る幕はありません。
「全部Service Objectで書きたい」なら、Form Objectを書くよりService Objectを書く方が気分がよいでしょう。
なおJavaで仕事をしている方ならyaaf gemは使いたくならないでしょうね。
yaafのささやかな経緯
私たちはまさにこれと同じアプローチをproductionアプリでほぼ1年間にわたって利用し、この方法で10を超えるForm Objectを書き、そしてうまくいっています。この機能をgemに切り出した理由はこれです(yaaf gemのコード量は現時点でわずか64行であり、私たちもこれ以上の機能は必要としていません)。
このgemをごく初期の段階からシェイプアップしてくれた@santibにひたすら感謝です!
yaaf gemの素敵なブランディングはSofi Salazarによるものです。