だるろぐ

明日できることは、今日しない。

寄り道: Rails の Flash っぽい機能を WebMatrix で使いたい

Flash っていうのは、別に Adobe Flash Player のことなんかじゃなくて、

  • ログイン時のウェルカムメッセージや、項目追加の成功通知など、ユーザに簡単な通知を行いたい時に利用する。
  • コントローラでflashメッセージを設定し、ビューで表示する。
  • flashは全体で見ればHash。あるキーに対する値としてメッセージを設定する。キーは自由に設定できるが、デフォルトとしてalertとnoticeがある。
  • 設定したメッセージは、sessionに保存される。つまり、flashは、sessionを利用した機能の1つ。
  • 普通のセッション変数では破棄するまで値は保持されるが、flash の場合は一度表示されるとアクション終了時に自動的に消去される。
flashの使い方 〜Railsの基礎 - プログラマーkkの勉強/成長ブログ@ライブレボリューション

というもの。ログアウト+ホームへリダイレクトしたときに「Good bye!」って表示したい(でも、一度表示したら二度目からは表示しない)なんて場合、あるよね。

ASP.NET Web Pages にもそういう仕組があるのかもしれないけれど、よくわからなかったので自分で実装してみた。本物の Flash はHash(C# なら Dictionary)らしいのだけれど、今回はそこまで高機能なのはいらないので、単に文字列を一つだけ保持することにする。

# Logout.cshtml

@{
    WebSecurity.Logout();
    Session["flash"] = "Good bye!"; // <-- ココ!
    Response.Redirect(Request["ReturnUrl"] ?? "~/");
}

実装には Session を利用した。 Session["flash"] にテキストを入れておけば、リダイレクトしたあとでも値を参照できる。

# _SiteLayout.cshtml

<body>
    @if (Session["flash"] != null)
    {
        <div class="message info">
            <p>@Session["flash"]</p> // <-- 読みだして……
        </div>
        Session["flash"] = null; // <-- 消す!……
    }

    @RenderBody()
</body>

表示する側では、かならず Session["flash"] をクリアしておく。これで Session["flash"] の内容が表示されるのは一度きりになるはず。

f:id:daruyanagi:20120829200628p:plain

これでいいのかは自信がないのだけれど、うまくいったのではないかな。

ステップアップ

ビューでぐちゃぐちゃコード書くのはあまり格好よくないから、これはぜひカプセル化しておきたいよね。ヘルパーにしておくとよさそうだ。

というわけで、 Flash ヘルパーを作ってみた。インターフェイスは単純で、 Write(string) で書き込んで、 Read() で読むだけ。読むと内容が破棄される。

# ~/App_Code/Flash.cshtml

@helper Read()
{
    if (Session["flash"] != null)
    {
        <div class="message info"><p>@Session["flash"]</p></div>
    }
    Session["flash"] = null;
}

@functions
{
    public static void Write(string value)
    {
        Session["flash"] = value;
    }
}

Helper はインスタンス作って使うわけじゃないから、 static で宣言せえへんだら外から使えへんで。で、これを使うと、

# Logout.cshtml

@{
    WebSecurity.Logout();
    Flash.Write("Good bye!"); // <-- ココ!
    Response.Redirect(Request["ReturnUrl"] ?? "~/");
}

で書いて、

# _SiteLayout.cshtml

<body>
    @Flash.Read() // <-- これ!

    @RenderBody()
</body>

で、読むって感じになる。結構簡単だったから、少し手を加えて Dictionary へ拡張してもいいかも。