Railsでモーダルの出し分けを管理する

Railsでモーダルの表示処理をまとめて衝突しないように管理する方法を紹介します。

背景

ツクリンクを運営する中でモーダルが少しづつ増え、衝突することがあったためモーダルの優先順位を付け、衝突しないよう実装をしました。

実装

前提

以下の3つのモーダルがあるとします。

  • A: 初回ログインで出すモーダル(全ページ)
  • B: 特定のユーザーにだけお知らせを出すモーダル(全ページ)
  • C: 特定のページで出すモーダル(Posts#show)

コードサンプル

全ページに出すモーダルはApplicationControllerで該当ユーザーか判断しモーダルに必要な情報をセットします。

# controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :set_modal_A
  before_action :set_modal_B

  def set_modal_A
    return if cookies['modal_A'].present? # 表示済みなら何もしない
    if is_first_signed_in? # 初回ログインか?
      @modal_A = { title: '表示に必要な情報など' }
    end
  end

  def set_modal_B
    return if cookies['modal_B'].present? # 表示済みなら何もしない
    if show_notice? # お知らせを出すユーザーか?
      @modal_B = true
    end
  end
end

Viewごとに出るモーダルは provide でモーダルをセット

# views/posts/show.html.erb
<% provide :modal, render('modal/C') %>

レイアウトのView(もしくはそれに準ずるパーシャル)でモーダルの出し分けを行います。 ifの上位にあるものが優先され、モーダルが複数renderされるのを防いでいます。

# views/layouts/application.html.erb
<% if yield(:modal).present? %>
  <%= yield(:modal) %>

<% elsif @modal_B.present? %>
  <%= render 'modal/B' %>
<% elsif @modal_A.present? %>
  <%= render 'modal/A' %>
<% end %>

各モーダルのViewでは表示を管理するCookieを保存するなどの処理をしています。

# views/modal/A.html.erb
<% cookies.permanent['modal_A'] = { value: true, expires: 1.day } %>
<div class="modal">お知らせだよ!</div>