LoginSignup
1
1

Rails7.0+Devise4.9をBootstrap5でカッコよくする

Last updated at Posted at 2023-06-12

はじめに

Rails 7.0.5、Bootstrap 5.2でDevise 4.9を動かすの続きです。今回はBootstrap5で昔のRailsLayoutに相当する部分を作ります。

環境
Rails 7.0.5
Ruby 3.1.2
Bootstrap 5.2.3
MySQL Ver 8.0.31 for macos13.0 on arm64 (Homebrew)
Mac OS Ventura 13.4

この記事が参考になってVPSにデプロイしたいと思った方はぜひ以下のリンクからVultr VPSを申し込んでみて下さい。

激安VPSのVultrで紹介者からのリンク経由でアカウント登録すると$100のクレジットをもらえるので、CentOS7, 8, MySQL 5.7, 8などの組み合わせをいろいろ試しました。このキャンペーンはいつ終わるか分からないので、興味のある方は以下のリンクからアカウント登録してください。あなたはクレジットをもらえるし、私にも多少のクレジットが入るらしいので、Win-Winです。

このリンクで$100もらえます

スクリーンショット 2023-06-11 午後12.24.36.png

私もリファラー経由でアカウントを作ったので$100もらえました。これで最初にあれやこれや試すのは無料でできます。
VultrCredit.png

関連記事

  1. Rails 7.0.5でBootstrap 5.2を動かす
  2. Rails 7.0.5、Bootstrap 5.2でDevise 4.9を動かす
  3. Rails7.0+Devise4.9をBootstrap5でカッコよくする (今回の記事)

1. Toastr

自分の趣味でトースターを入れてみた。

(1) Toastrのインストール

Gemfile
# Toastr
gem 'toastr_rails'
rails_root
$ bundle install

Installing toastr_rails 2.1.3
Bundle complete! 24 Gemfile dependencies, 94 gems now installed.
Bundled gems are installed into `./vendor/bundle`

(2) Toastrの構成

app/assets/javascripts/application.js
//= require toastr_rails
app/assets/stylesheets/application.scss
@import "toastr";

(3) ViewにToasterを追加

</body>の上にスクリプトを追加。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Device490</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %>
  </head>

  <body>

    <%= yield %>

    <%# ------ Toastr ----- %>
    <% if flash.any? %>
    <script type="text/javascript">
        <% flash.each do |key, value| %>
        <% key = "success" if key == "notice" %>
        <% key = "error" if key == "alert" %>
        <% key = "error" if key == "warn" %>
        toastr['<%= key %>']('<%= value %>');
        <% end %>
    </script>
  <% end %>
  <%# ------ Toastr ----- %>

  </body>
</html>

(4) 動作確認

動きました。

スクリーンショット 2023-06-12 午前12.46.56.png

2. Bootstrap5 Navbar

RailsLayoutがBootstrap5に対応してれば一発でとりあえずの雛形まで作成できるのだが、残念ながらRailsLayoutは開発が止まっているので、Bootstrap4対応のRailsLayoutで作成されたものをBootstrap5に書き換える。

(1) Navbar

application.html.erb

最上部にNavbarを出したいのでapplication.html.erbにNavbar用のERBファイルを呼び出すように<%= render 'layouts/navigation' %>を入れる。同時に<body> </body>の間にWrapperを入れておく。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Device490</title>
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>

  <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %>
</head>

<body>
<div id="wrapper"> <%# --- BEGIN of wrapper --- %>
  <header>
    <%= render 'layouts/navigation' %>
  </header>

  <%= yield %>

  <%# ------ Toastr ----- %>
  <% if flash.any? %>
    <script type="text/javascript">
        <% flash.each do |key, value| %>
        <% key = "success" if key == "notice" %>
        <% key = "error" if key == "alert" %>
        <% key = "error" if key == "warn" %>
        toastr['<%= key %>']('<%= value %>');
        <% end %>
    </script>
  <% end %>
  <%# ------ Toastr ----- %>

</div> <%# --- END of wrapper --- %>
</body>
</html>

_navigation.html.erb

Navbarを作り出す部分がこのファイルとなる。細かい説明は省略するがBootstrap5公式サイト(あるいはその翻訳サイト)でNavbarのサンプルがあるので、ここではそれをほぼそのまま使っている。

app/views/layouts/_navigation.html.erb
<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <%= link_to 'MY COMPANY', root_path, class: 'navbar-brand' %>

    <button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#Navber" aria-controls="Navber" aria-expanded="false" aria-label="ナビゲーションの切替">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="Navber">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item dropdown">
          <a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Menu
          </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Item</a></li>
            <li><a class="dropdown-item" href="#">Item</a></li>
            <li><a class="dropdown-item" href="#">Item</a></li>
            <li><hr class="dropdown-divider"></li>
            <li><a class="dropdown-item" href="#">Item</a></li>
          </ul>
        </li>
        <li class="nav-item dropdown">
          <a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Menu
          </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Item</a></li>
            <li><a class="dropdown-item" href="#">Item</a></li>
            <li><a class="dropdown-item" href="#">Item</a></li>
            <li><hr class="dropdown-divider"></li>
            <li><a class="dropdown-item" href="#">Item</a></li>
          </ul>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Menu</a>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled">FAQ</a>
        </li>
      </ul>

      <%= render 'layouts/nav_links_for_auth' %>

    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

_nav_links_for_auth.html.erb

app/views/layouts/_nav_links_for_auth.html.erb
<% if user_signed_in? %>
  <ul class="nav-item dropdown mb-2 mb-lg-0">
    <a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
      <%= t('nav_hello') %>
      <% if params[:locale] == 'ja' %>
        <%= current_user.LastName %><%= t('nav_honorific') %>
      <% else %>
        <%= current_user.FirstName %>
      <% end %>
    </a>
    <ul class="dropdown-menu">
      <li>
        <%= link_to root_path, class: 'dropdown-item' do %>
          <i class="fa-solid fa-tachograph-digital"></i> Menu
        <% end %>
      </li>
      <li>
        <%= link_to root_path, class: 'dropdown-item' do %>
          <i class="fa-solid fa-envelope"></i> Menu
        <% end %>
      </li>
      <li>
        <%= link_to destroy_user_session_path, data: { turbo_method: :delete }, class: 'dropdown-item' do %>
          <i class="fa-solid fa-right-from-bracket"></i>
          <span id="logout_link"><%= t('devise.shared.links.sign_out') %></span>
        <% end %>
      </li>
    </ul>
  </ul>
<% else %>
  <%= link_to t('devise.registrations.new.sign_up'), new_user_registration_path, class: 'btn btn-outline-primary' %>
  <ul class="nav-item dropdown mb-2 mb-lg-0">
    <a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
      <i class="fa-solid fa-user-large fa-lg"></i>
    </a>
    <ul class="dropdown-menu dropdown-menu-end">
      <li>
        <%= link_to new_user_session_path, class: 'dropdown-item' do %>
          <i class="fas fa-sign-in-alt ml-1"></i><span id="login_link"><%= t('devise.shared.links.sign_in') %></span>
        <% end %>
      </li>
    </ul>
  </ul>
<% end %>

(2) font-awesome-sassをインストール

font-awesome-sassをインストールします。

Gemfile
# Font Awesome
gem "font-awesome-sass", "~> 6.4.0"
$ bundle install

Installing font-awesome-sass 6.4.0
Bundle complete! 25 Gemfile dependencies, 95 gems now installed.
Bundled gems are installed into `./vendor/bundle`
app/assets/stylesheets/application.scss
@import 'font-awesome';

ここまでの作業でTopページ画面はこんな感じです。

スクリーンショット 2023-06-12 午前1.51.32.png

(3) Deviseの各Viewを中央寄せ

このままだとDeviseの各Viewが左寄せされてしまって見にくいので各Viewを<div class="main-container mb-5"> 〜</div>で挟み込みます。このCSSも載せておきます。

例えばログイン画面は次の通りです。

app/views/devise/sessions/new.html.erb
<div class="main-container mb-5">
  <div class="row">
    <div class="col-md-6">
      <h2 class="pb-4"><%= t('.sign_in') %></h2>

      <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
        <div class="mb-3">
          <%= f.label :email, class: "form-label" %>
          <%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control' %>
        </div>

        <div class="mb-3">
          <%= f.label :password, class: "form-label" %>
          <%= f.password_field :password, autocomplete: "current-password", class: 'form-control' %>
        </div>

        <% if devise_mapping.rememberable? %>
          <div class="mb-3 form-check">
            <%= f.check_box :remember_me, class: 'form-check-input' %>
            <%= f.label :remember_me, class: 'form-check-label' %>
          </div>
        <% end %>

        <div class="mb-4 mt-4">
          <%= f.submit t('.sign_in'), class: "btn btn-primary" %>
        </div>
      <% end %>

      <%= render "devise/shared/links" %>
    </div>
  </div>
</div>

使っているSCSS

app/assets/stylesheets/pages.scss
// Place all the styles related to the Pages controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: https://sass-lang.com/

.main-container-bg{
   padding-top: 28px; // 固定されたナビバーの高さの分だけ上にずれてしまうため、bodypadding-topで調整する。
   background:#ddd center center / cover no-repeat fixed;
   background-size:cover;
   width: 100vw;
   height: 100vh;
   position: relative;
   text-align: center;
}

.main-container {
  margin-top: 56px; // 固定されたナビバーの高さの分だけ上にずれてしまうため、bodypadding-topで調整する。
  margin-left: auto;
  margin-right: auto;
  width: 75%;
}

.sub-container{
  width: 100vw;
  text-align: center;
  position: absolute;
  top: 40%;
  -webkit-transform : translateY(-50%);
  transform : translateY(-50%);
  color: #FFFFFF;
  text-shadow:1px 1px 0 #000, -1px -1px 0 #000,
  -1px 1px 0 #000, 1px -1px 0 #000,
  0px 1px 0 #000,  0-1px 0 #000,
  -1px 0 0 #000, 1px 0 0 #000;
}

body,
#wrapper {
  //padding-top: 28px; // 固定されたナビバーの高さの分だけ上にずれてしまうため、bodypadding-topで調整する。
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background-color: white;
}

footer {
  margin-top: auto;
}

// For Devise Sign-in
.form-signin {
  width: auto;
  padding: 19px 29px 29px;
  margin: 40px auto 20px;
  background-color: #fff;
  border: 1px solid #e5e5e5;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
  -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05);
  -moz-box-shadow: 0 1px 2px rgba(0,0,0,.05);
  box-shadow: 0 1px 2px rgba(0,0,0,.05);
}

.form-signin .form-signin-heading,
.form-signin .checkbox {
  margin-bottom: 10px;
}

.form-signin input[type="email"],
.form-signin input[type="password"] {
  font-size: 16px;
  height: auto;
  margin-bottom: 15px;
  padding: 7px 9px;
}

// https://yukimasablog.com/rails-field-with-errors
.field_with_errors {
  display: contents;
  // もしくは diplay: inline;
}

上記CSSの読み込み

app/assets/stylesheets/
@import 'pages';

ここまでの作業でログイン画面はこんな感じになりました。

スクリーンショット 2023-06-12 午前2.11.56.png

3. 更なるカスタマイズ

ここから先は好みが分かれるでしょうし記事の趣旨であるRailsLayout相当の見た目のBootstrap5への実装としては上記までで終わりなのですが、Deviseのエラーメッセージの取り扱い等をもっとカッコよくするカスタマイズを次回の記事で書きたいと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1