バッドノウハウ:Railsで他のアプリケーションとセッションを共有するために
Rails ではセッションにモデルのインスタンスをぶち込んだりできるのですが,例えば複数のアプリケーションでログイン情報を共有するためにセッションを使ったりすると,モデルのクラス定義が存在しないとエラーになってしまいます.
アプリA -> User, Blog, Entry アプリB -> User, Friend, Photo in アプリA: session[:new_entry] = Entry.new to アプリB: Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: ERRORMESSAGE [Entry])\n
本来はこれは正しい動作なのですが,古いアプリなどで仕方なく連携する場合など困る場面もあります*1.そこで仕方なく,例外を発生させずに空のクラスを定義することで回避します.
module ActionController module Session class AbstractStore class SessionHash < Hash private def stale_session_check! yield rescue ArgumentError => argument_error if argument_error.message =~ %r{undefined class/module ([\w:]*\w)} begin # Note that the regexp does not allow $1 to end with a ':' $1.constantize rescue LoadError, NameError => const_error eval(%Q{class #{$1}; def unused; true; end; end}, TOPLEVEL_BINDING) #raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n" end retry else raise end end end end end end
ただこれだけだといろいろ問題になるので,この処理で定義した空クラスを削除します.app/controllers/application_controller.rb などで before_filter を定義して削除します.
def remove_unused_session # セッション読み込み時に生成した class のデータを削除 session.to_hash.each{|k, d| session[k] = nil if session[k].respond_to?(:unused)} end
あまり使わない方がいいノウハウですが,システム移行などでどうしてもと言う場合には使えるので,こういう手もあると覚えておくのはいいんじゃないでしょうか.