Railsでドメインロジックをモデルに書くのは、果たして良い設計なのだろうか?

Railsの”モデル”は責務を持ちすぎでは無いだろうか?

RailsのActive Recordはエンティティ(テーブル)とロジックを1対1に縛って、1枚岩の”モデル”と呼ぶオブジェクトとして扱っている。単純な場合は1対1で、多少の複雑さであればActive Recordは非常に便利なAPIを提供してくれて、開発効率をグンと上げてくれる。

しかし、ある程度の複雑度が出てくるとドメインロジックはエンティティと1対1に対応しなくなるし、それを扱う側(Controllerなど)によってロジックが変わることもある。

単純にFat modelに従えば、どちらか一方のモデルのメソッドとしてロジックを隠蔽する。そのため、複数のモデルの操作をしているにも関わらず、様々なデータ操作の責務を1つのモデルが抱えてしまう。これをControllerやViewで扱う時には、操作するオブジェクトが直感的で無く扱いづらい。

(例えば、複数のエンティティのデータを複合した集計なのに、一方のモデルのメソッドから取ってくる場合、1つのフォームから複数のモデルに対してアクセスする場合。)

かといってControllerに書いたら、DRYではない。

 

この1枚岩になっているエンティティとドメインロジックを、切り離してそれぞれ別のオブジェクトにした方が良いのではないだろうか?

この問題についてずっと考えてきた個人的な結論としては、ModelとControllerの中間層にオブジェクトが介在して、このオブジェクトがビジネスロジックの責務を持つのが良いのではないか?と考えてきた。

ふとSQLアンチパターンを呼んだところ、まさにActive Recordパターンのこの問題について言及している章があった。(24章:マジックビーンズ)SQLアンチパターンで提示されている解決策としても、エンティティ=アクティブレコード, ドメインロジック=ドメインモデルとして分離することを推奨していた。

 

ところで、1枚岩のActive Recordの機能をバラして使おうとする(Active Modelなど)とActive RecordやRailsの恩恵が犠牲になってしまう。(文字通りレールから逸れている)
ここをうまく切り抜けるにはどうしよう…というところ。うまくRailsのAPIを吸収して、ドメインモデルを分離したい。
この辺りに取り組んだ事例などが知りたい…

追記(12/11)

a_suenamiさんから、アドバイス記事をいただきました!

Rails でドメインロジックの実装方法まとめ

他にも参考になる記事があったので紹介します。

肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)

 

【jQuery】selectボックスのchangeイベントを検知できない

jQueryを用いて,selectボックスの値に応じて何かしたいというパターンは多いですよね.jQuery.changeを用いればselectボックスの値の変更を検知することができます.

しかし,他のイベントと異なりjQuery.changeは定義の仕方を誤ると動作しません.

【動かない例】

(function() {
  $('#sample_select').change(function() {
    // 内容
  }));
)(jQuery);

【正しいコード】

そのままでは動かなかったので,jQuery.readyを使う必要があります.(よくよく考えてみれば,DOMの読み込みが完了してからセレクタを使わないとダメですよね…)

jQuery.readyは以下の様にも記述できます.

$(function($) {
  $('#sample_select').change(function() {
    // 内容
  });
});

jQueryを使うときは,基本的にはjQuery.ready(function() {})あるいは$(function() {})で囲むように注意しましょう.

Bundlerを利用したRailsプロジェクトの作成方法

Railsでは様々なgemを利用します。 各gemのペースでどんどんバージョンが上がっていくため、異なるバージョンのgemと組み合わせると、うまく動作しないことがあります。 そこで、bundlerを使うことで、使うgemのバージョンを固定することができます。

Continue reading

OAuthにはCallback URLを必ずセットする

RailsアプリにOmniAuthでTwitterのOAuth認証を実装したときにハマった点です.

TwitterのOAuthのCallbackURLは必ずセットしよう

CallbackURLの入力欄は,必須になっていないし,本番環境じゃないし・・・ということでCallbackURLをセットしなかったのですが,これが原因で「401 Unauthorized」エラーに悩まされていました.

しかし,これを入力しないとどうやらダメなようです.
http://taksatou.blogspot.com/2011/03/twitterfacebookrails.html

そういえば,先輩が似たような事を以前に言っていた様な気がしたので,ブログを漁ってみたらありました.
http://d.hatena.ne.jp/yayugu/20110813/1313220348

きっとみんなハマるよね!