ときたまセッションに関連するロジックをモデルの中に作りたいときがある。ところが、原則的にRailsではセッションをモデルの中で操作することができない。
この問題を解決する最も簡単な方法は、モデルに生やしたメソッドへセッションのインスタンスを渡す引数を追加し、それを経由してロジックを書くというものだ。
class User < ActiveRecord def your_method(session, count) session[:items_count] = count end end
こうすることで、やりたいことは実現できる。
... def update user.your_method(session, count) end ...
SRP(単一責任の原則)に則る
これによって、実際にやりたいことは実現されたが、上のコードはSRP(単一責任の原則)から見て必ずしも正しいものではない。 基本的にはActiveRecordパターンであるRailsのモデルには、そのモデルが1:1で紐づく入出力すなわちデータベース・テーブルへの、アクセスオブジェクトとしての役割がある。セッションも見方を変えれば、小さく揮発性の高いストレージのひとつであるが、ひとつのモデルにいくつもの永続化のロジックが混入するのは責務の観点からみて適切ではない。こうした実装は、テストを書く際やアプリケーションのスケールの際に問題になりやすい。
こうした問題を解決するひとつの方法として、セッションを扱うロジックをカプセル化し、責務を分離することで、疎結合な実装にすることができる。
class TemporaryCart def initialize(session) @session = session end def add_item @session[:temprary_cart][:items_count] += 1 end end
TempraryCard
クラスを実装したことによって、コントローラは以下のようになる。
... def update TemporaryCart.new(session).add_item end ...
セッションの永続化モジュールがモデルから分離されたことで、見通しの良いコードベースになった。モデルがそれ自体の正しい責務を守ることは「驚き最小の原則」にも則るという面で利点がある。