状況
Ruby on RailsとNode.jsでセッションデータを共有したい状況がありました。
Session StoreにはRedisを使っています。
普通に考えると、クッキーからセッションID取って当てに行けばいけるだろうと考えるのですが、Railsは一筋縄ではいきません。
中身覗くとすぐ分かるんですが、セッションデータ自体がMarshalでシリアライズされた状態で保持されている為。
Node側でデータとってもJSONでパースできないし、なんだこりゃ?となります。
さてどうするか、となった時に参考にさせていただいた記事がこちら(感謝)↓
ふむふむなるほど。
JSONがやっぱり扱いやすいので、この方法を使ってJSON形式に変更しました。
すると、Node側でもJSONでとれたし、Rails側もうまく動いてる。
やったやったと思っていたのですが、実はこのときはまだRails3。
Ruby2.0、Rails4.0
それからいくつかの時間が経ち、このプロジェクトをRuby2.0、Rails4.0で動くようにしようと思い、諸々修正したりなんだかんだしました。
あれやこれやで、セッション周り以外はうまく動くようになりました。
セッションも、普通にログイン保持やNodeとの連携も出来てていい感じだと思ってたのですが、よーく見てみたら・・・
flash[:notice]とかでメッセージ出てきてない!
ってことに気づきました。
メッセージ(通知含む)をタスクの順序の関係で後回しにしていて、後になって発覚しました。
上記の参考記事内でも触れられているように、flashはちょっと特殊みたいで。
Rails3の時のセッションJSON化の時にもそこは追っていて、あー、4になったからなんかあるのかなーと。
さらには、flashに値をセットするアクションを何回か通っていると、不思議な例外が出るようにもなりました。
セッションの値をパースできない、といったような例外だったと思います。
こうなると、もう何をやってもエラー画面にしかならず、CookieのセッションIDを削除してやらないと先に進みません。
何故こうなったか、セッションの中身を見てみるとFlashHashに関係するdiscard, flashesといったHashがHashとArrayの不思議な入れ子状態で、何階層にも渡って保持されてしまっていました。
明らかにflash周りで何か起こっています。
ソースを覗く
で、こういう時はソースを・・・と思い、見てみました。
・・・
7行目からいきなり違いますね・・・
4.0でのセッションのflashはHashのままでもそこからFlashHashオブジェクトを生成してくれる
Flash::FlashHash.from_session_value
というファクトリーメソッドがあって、7行目でそのあたりを吸収してくれています。
ほんと、最初はセッションデータをunmarshalしたりするとこで、Hash -> FlashHashにうまいこと出来てないんじゃないかとかばかり見ていて、どうにもうまく行かなかった。。。
あーあ〜、やっぱりちゃんと中身を確認しないとなーと、改めて思いました。
ちなみに・・・
このセッションをJSONで保持しているときのflashの出し方は
flash[:notice]
ではなくflash["notice"]
にしないとメッセージ出ません。
(ここでも地味にハマりました)
シンボルのままflash[:notice]
で出せるやり方を知っている方がいましたら是非教えていただきたいです。
ついでに
調査していたら、セッションデータのmarshal、unmarshalでのJSONの変換箇所、実装方法でシンプルだなって思うのを見つけました。
上記の記事で紹介されているやり方が結局一番シンプルだなーと思いました(感謝)。
ハマったことの解決策のまとめ
- Rails4でセッションデータをJSONで保持するように変更しても、ActionDispatch::Flash::FlashHashに戻す必要はなくHashのままでOK。
- 出力の際のキーはシンボルではなく文字列で(flash[“notice”]等)。 ※←今のところ。