リソースとテーブルのギャップを飛び越える
はじめに
第3回の今回は、正規化された「テーブル」と、人間にとって分かりやすい「画面」。このギャップを超えるための中間層について解説します。
Railsによる開発では、テーブルの構造に従って、入力項目や画面遷移といったインタフェースの仕様が決まります。具体的には、あるテーブルの名前が確定すると、それに沿ってモデルやコントローラの名前が決まり、テーブルの属性によって、画面の入出力項目が決まります。さらに、モデルの関連や振る舞いに従って、定義するアクション、画面遷移、ルーティングが決まります。
この様子を、次の図1に示します。
図1: テーブル構造からインタフェースが確定していく様子 |
このように、テーブル構造とインタフェースを直結してサクサクとアプリケーションを作成していくのが、Rails開発の面白さです。
しかし、よく考えてみると、「テーブル」とは、正規化された、いわば「コンピュータにとって分かりやすい」構造です。そのままだと、使いづらいアプリケーションや複雑な処理となってしまいます。
一方、「画面」は、「人間にとって分かりやすい」冗長な構造です。こちらは、正規化されていないテーブル定義になりがちです。
テーブルと画面にまたがる、このギャップを超えるためには、モデルとコントローラの間に立って構造の違いを吸収してくれるような「中間層」を設ける必要があります。
中間層の重要性
別の角度から、中間層の重要性を見ていきましょう。
アクティブ・レコード・パターンでは、対応するテーブルに関連する操作を1つに集約します。これには、複数のテーブルを操作する時のロジックの置き場所が難しい、という弱点があります。第1回で示したように、アクションの中にロジックを記述してしまいがちです。この結果、コントローラが、その責務を超えてトランザクションを実行するような状態になります。
この問題は、複数テーブルを扱う中間層が不在であることに起因している、と言えます。
また、Railsでは、数行の設定を定義するだけで、画面を、XMLやJSONを受け付けるWebサービスとして動作させることができます。このケースでも、中間層の不在が問題となります。
例えば、商品を販売するというサービスにおいて、以下の処理を行うと仮定します。
- 在庫を表現するテーブルを参照して、指定された量が存在することを確認する
- 在庫から販売した量を減らした上で、発送を表現するテーブルに、あて先を記録する
- 収益を表現するテーブルに、金額を加える
- そのほか、注文書の記録などを行う
これを、次の図2に示すように、テーブルごとに個別にリソースを定義してしまったとします。こうすると、エラー発生時に登録内容を差し戻す処理などによって、非常に複雑になってしまいます。上記の処理を一括して行う中間層を用意するのが望ましい、と言えます。
図2: テーブルごとにリソースを定義した様子 |
では、どのように中間層を実現すればよいでしょうか。中間層を表現する方法はさまざまですが、今回は、これまで解説してきた「ActiveRecord」を活用して実現してみます。
サンプルについて
以降では、上記で述べた販売処理を例に、具体的なコードを使って解説します。本処理で扱うテーブル群と、販売に対応するリソースの構成を、次の図3に示します。あまり現実的ではないテーブル構成ですが、属性の合成とテーブル間をまたがった処理に対する、良い例になると考えます。サンプルを読み進める中で、参考にしてください。
図3: サンプル・コードで扱うテーブル群と販売リソースの関係 |