私にはこのブログを書く権限がない。

Twitterじゃ書ききれない何かを書くアレ

MVCとRails

普段Railsで、特にscaffoldを使って何かを作っていると、MVCモデルについて色々誤解してしまうことがある。ちょっと機会が有ったので、ここでMVCモデルについてもう一度復習しておくことにする。

そもそもMVCとは何か

wikipedia:Model View Controllerによれば

Model View Controller(モデル・ビュー・コントローラ; MVC)は、コンピュータ内部のデータをユーザに提示し、それに対してユーザが何らかの指示を出すタイプの、独自のユーザーインタフェースをもつアプリケーションソフトウェアを、以下に述べるようなmodel・view・controllerの3つの部分に分割して設計・実装するという技法、又はそのような構造をいう。

とある。アプリケーションソフトウェアを分割するするのであって、オブジェクトを分割するというわけではないのだ。
つまるところ、1つのビューが複数のモデルを参照しても構わないし、1つのコントローラで複数のモデルを使っても構わないのだ。

Model=レコードではない

再度、wikipedia:Model View Controllerから引用しよう。

Model

そのアプリケーションが扱う領域のデータと手続き(ビジネスロジック - ショッピングの合計額や送料を計算するなど)を表現する要素である。また、データの変更をviewに通知するのもmodelの責任である(modelの変更を通知するのにObserver パターンが用いられることもある)。
多くのアプリケーションではデータの格納に永続的な記憶の仕組み(データベースなど)が使われている。MVCの概念では、データの(UI以外の)入出力は取り扱わないので、データアクセスも本来MVCの概念の範疇を超えるものではあるが、敢えていえばmodelの中に隠蔽されると考えられる。

Railsでは通常、Controller内でデータの書き込みを行い、Modelでは:has_many等のデータに対する属性付与(?)しかコードを書かない。
その上、Model.newによってレコードを新規作成したり、model.save!でレコードを保存している為、Model=レコードだという誤解を産んでしまう(酷い人は、Modelを「データの設定をするための何か」程度の認識かもしれない)。
そのため、Model=レコードと勘違いしがちである。
各ModelクラスではActiveRecordクラスを魔法の言葉のごとく継承しているが、ActiveRecordクラスはデータベースとのやりとりを行うクラスであり、つまりMVCにおけるModelの大部分をActiveRecordが行なっている。
RailsにおけるModelはあくまで「データベースとデータのやり取りを行う」ものであって、「データベース上のデータそのもの」ではないのだ。

Controllerの本来の役割

先ほど、「Railsにおける」というのを強調したが、これには少し理由がある。
Railsにおいて、フォーム等から入力されたデータをデータベース上に保存する際、データベース上に保存する前にデータに何らかの処理を行わなければいけない場合、Controllerでそのデータを処理する人が多いのではないのだろうか。
しかし、この方法はMVC的には全く正しくない。なぜなら、MVCにおけるControllerは「ユーザからの入力を受理する」ということだけが本来の役割であって、データの整形はModelの仕事だからである。
ではなぜ、Controllerでそれらの処理を行う人が多いのだろうか。理由は簡単で、scaffoldによってgenerateされたControllerにおいては「データの整形を行ってからデータベースに保存する」という行為が想定されておらず、model.save!によって受け取った引数をそのまま保存するテンプレートを生成するからである。
MVC的に正しいやり方は「Model内にデータを整形し、保存するというメソッドを追加し、Controllerからそれを呼び出す」ことなのだろうが、それが面倒 or コードが汚くなるという思想があるのだろう。
したがって、Railsにおいてのみ、データの整形をControllerにまかせる、というのが一般的となっている。
Java等の他の言語やフレームワークMVCで書くときは、データの整形はModelにさせるべきなのだ。

最後に

Railsをdisっているような感じの記事となってしまったが、僕が言いたいのはRailsは「Model View Controller」という名称を辞めて、「Data View Engine」のような感じで別の名称にするべきであるということだけであって、Railsを辞めて別のフレームワークを使いましょうというわけではない。むしろ、「Webフレームワークは何が一番いい?」と聞かれたら、真っ先に「Rails」と言えるくらいには自分はRails好きなので、そこだけは誤解しないでいただきたい。