Runner in the High

技術のことをかくこころみ

モデルの中でセッションを使う

ときたまセッションに関連するロジックをモデルの中に作りたいときがある。ところが、原則的に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
...

セッションの永続化モジュールがモデルから分離されたことで、見通しの良いコードベースになった。モデルがそれ自体の正しい責務を守ることは「驚き最小の原則」にも則るという面で利点がある。

参考: Setting a Session Variable in a Model - Stack Overflow