Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails: シンプルなForm Object gem「yaaf」(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。

Rails: シンプルなForm Object gem「yaaf」(翻訳)

RailsアプリでForm Objectパターンを使いやすくするyaafというgemをご紹介します。

rootstrap/yaaf - GitHub

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に失敗した場合はデータベースロールバックもトリガーされます。つまりsavesave!のどちらも使えるのです。

オブジェクト作成に関連するビジネスロジックの置き場に迷う: 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

yaaf gemの素敵なブランディングはSofi Salazarによるものです。

rootstrap/yaaf - GitHub

関連記事

私はnilを使わない(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。