ボクココ

個人開発に関するテックブログ

Ruby on Rails で自前トーストを作るサンプル

ども、@kimihom です。

f:id:cevid_cpp:20190407182905p:plain

Rails で開発をしていると、何かしらのメッセージをユーザーに掲示したい時がよく出てくる。

  • コンタクトを作成しました。
  • メンバーの招待に失敗しました。
  • アイテムを更新しました。

こういったときに flash っていう便利なメッセージ保存場所があるのはご存知かと思う。

flash - リファレンス - - Railsドキュメント

ただ、この Flash を View で普通に使うだけだと、Ajax リクエストした場合には Flash 表示させることができない。この問題を解決すべく、JavaScript 上でもトーストを同じように出せるような実装をしてみようというのが今回のテーマである。

トースト HTML の用意

まずはデフォルトで非表示のトーストの HTML をレイアウトに埋め込もう。CSS もよしなに用意しておく(padding とか細かいのは省略)。

<div id="common-messages">
  <p class="notice corner <%= "active" if notice %>"><span class="msg"><%= notice %></span></p>
  <p class="alert corner <%= "active" if alert %>"><span class="msg"><%= alert %></span></p>
</div>
#common-messages {
  position: relative;
  p {
    position: fixed;
    top: 12px;
    color: #ffffff;
    display: none;
    z-index: 99;
    &.notice {
      background-color: #009DB0;
    }
    &.alert {
      background-color: #de4437;
    }
    &.active {
      display: block;
    }
  }
}

もし noticealert の flash があれば、クラスを active にしておくのがポイントだ。まずはこれだけで、controller 側で flash が設定されていた場合の表示に備えられる。

では、JavaScript 側で任意のタイミングでトーストを表示させるようにしてみよう。

Toast = (function() {

  function show(target, text) {
    var $target = $("#common-messages ." + target);
    $("#common-messages ." + target + " .msg").text(text);
    $target.addClass("active");
    willHide();
  }

  var timeout = null;
  function willHide() {
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(function() {
      $("#common-messages .active").removeClass("active");
      timeout = null;
    }, 5000);
  }

  return {
    show: show
  };
}());

$(function() {
  // default toast hide
  Toast.willHide();
})

Toast.show("alert", "アラートメッセージだよ"); を呼ぶと、見事 JavaScript 側で任意のタイミングで同じトーストを呼び出すことができる。とりわけ、Ajax で送信したレスポンスでトースト表示させたい時などには便利に使えるだろう。 5秒後に勝手に非表示になるような実装にしているが、これは場合によっては x クリックした時だけ非表示にするなどの実装に変えることもあるかもしれない。

基本的な利用方針

普通にページ遷移するケースでは、JavaScript 側で呼ぶよりかは flash[:notice] などにセットしておいたほうが見通しが良くなる。とりわけ I18n で言語の切り替えをしている場合には、なおさら flash に詰めた方が楽だ。

もし JavaScript 側の結果メッセージなど、どうしても flash が使えない場合にだけ JavaScript 側で Toast.show を呼ぶようにしよう。この場合の I18n は別途、以下のような 言語対応の View を用意する必要が出てくるだろう。

<div style="display: none;">
  <span id="locale-created"><%= t('msg.created') %></span>
  <span id="locale-updated"><%= t('msg.updated') %></span>
  <span id="locale-deleted"><%= t('msg.deleted') %></span>
</div>

そんで、指定した要素の中身を Toast で表示するようにする。

Toast.show("notice", $("#locale-created").text());

I18n を気にしないなら、そのまま Toast に日本語を放り投げれば OK である。

終わりに

強化された自前トーストは、ページ遷移時のアラートだけでなく、JavaScript 側で起きたイベント時にもアラートを出すことを可能にした。今宵、JavaScript で色々なイベントが発生するようになってきているので、こうした対応は Rails で開発をしていると必要になる事項となるだろう。

適切なメッセージを表示させて、ユーザーに快適に Web アプリケーションを使ってもらえるようにしよう。

現場で使える Ruby on Rails 5速習実践ガイド

現場で使える Ruby on Rails 5速習実践ガイド

  • 作者: 大場寧子,松本拓也,櫻井達生,小田井優,大塚隆弘,依光奏江,銭神裕宜,小芝美由紀
  • 出版社/メーカー: マイナビ出版
  • 発売日: 2018/10/19
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る