58
8

【Rails6】Action Text × Bootstrap(4系) Webpacker管理だと相性悪すぎる件

Last updated at Posted at 2023-12-23

はじめに

こんにちは!

DMM WEBCAMP Advent Calendar 2023 :christmas_tree: 24日目も、同じく @Keichan_15 が担当させて頂きます!:v:

今回はやはり普段Railsをお教えしている身として、ちゃんとRailsに関する記事を書こうかなと…:thinking:

ところで、皆さんは Action Text と呼ばれるRails6から追加された新機能についてご存じでしょうか。
Action Textはリッチテキストを編集するための便利なエディター で、通常よりもモダンなフォームを作成することができるエディターです。

こんな感じのヤツ ↓

image.png

とても便利な機能なのですが、実はWebpacker側でBootstrapを管理している状態で共存させると… ↓

image.png

モダン云々のレベルを超えてる こんな感じで酷過ぎる画面にダウングレードします。おいAction Text!仕事せえ!:zipper_mouth:

そこで本記事では、

  • この現象が発生するパターンってどんな時?
  • BootstrapをWebpacker側で管理する場合でも、共存して表示できるようにするには?

上記2つに絞ってご紹介していきたいと思います!:raised_hands:

早速リッチテキストエディタを復活させる旅の出発です!!

環境

  • Ruby(3.1.2)
  • Rails(6.1.7.6)
  • Node.js(16.18.0)
  • Bootstrap(4.6.2)
  • WSL2(Ubuntu 20.04.5 LTS)
  • Visual Studio Code

事前準備

今回はAction Textを動作させるために、シンプルなタスク管理アプリケーションを作成しました。

image.png

今回、Rails6からデフォルトで入っている Webpackerを用いてBootstrapを管理する手法を取っていた としましょう。

要するに以下のような形で app/javascript配下でCSS, JS周りを管理しているパターンですね。

image.png

導入方法について細かく知りたい場合は、以下にて紹介されています!

今回はこちらの記事を参考に、若干アレンジを加えて導入しています。

terminal
$ yarn add jquery bootstrap@4.6.2 popper.js
config/webpack/environment.js
const webpack = require('webpack')
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: 'popper.js'
  })
)

application.scssについては別途、新規作成が必要です。

app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';
app/javascript/packs/application.js
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application"; 

Rails.start()
Turbolinks.start()
ActiveStorage.start()
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>TestApp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>
config/routes.rb
Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  resources :tasks
end

これで最低限、Bootstrapを使用する準備が整いました!:raised_hands:

Model & Controller & View 作成

では早速Action Textを使用してみましょう!

導入手順はRailsガイドを参考にしながら進めていきます!

まずAction Textをインストールします。

terminal
$ rails action_text:install

インストールが完了すると同時に、application.jsに以下の記述が追加されていることを確認します。

app/javascript/packs/application.js
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application"; 

Rails.start()
Turbolinks.start()
ActiveStorage.start()

// この2行が自動で追加されていることを確認!
+ require("trix")
+ require("@rails/actiontext")

次にModelを作成します。

今回はシンプルなタスク管理のアプリケーションのため、Taskという命名のModelを作成しました。

terminal
$ rails g model Task

カラムは以下を用意しました。

  • title : タスクのタイトル
db/migrate/hogehoge_create_tasks.rb
class CreateTasks < ActiveRecord::Migration[6.1]
  def change
    create_table :tasks do |t|
      t.string :title
      t.timestamps
    end
  end
end
terminal
$ rails db:migrate

今回はこのTaskというモデルに、リッチテキストエディタのフィールドを追加します。

task.rbに以下の1行を追加します。

app/models/task.rb
class Task < ApplicationRecord

+  has_rich_text :content

end

次にViewを作成します。

app/views/tasks/index.html.erb
<div class="container">
  <div class="row">
    <div class="col-md-12">
    <% @tasks.each do |task| %>
      <table class="table">
        <thead>
          <tr>
            <th>Title</th>
            <th>Body</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><%= task.title %></td>
            <td><%= task.body %></td>
            <td><%= task.content %></td>
          </tr>
        </tbody>
      </table>
    <% end %>
    </div>
  </div>

  <div class="row">
    <div class="col-md-12">
      <h2>New Task</h2>
      
      <%= form_with model: @task do |f| %>
      <div class="form-group">
        <%= f.label :title %>
        <%= f.text_field :title, class: "form-control" %>
      </div>

      <div class="form-group">
        <%= f.label :content %>
        <%= f.rich_text_area :content, class: "form-control" %>
      </div>

      <div class="form-group">
        <%= f.submit 'Create Task', class: "btn btn-success" %>
      </div>
      <% end %>
    </div>
  </div>
</div>

最後にControllerを作成し、タスク投稿機能を実装していきましょう!

terminal
$ rails g controller tasks
app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
    @tasks = Task.all
    @task = Task.new
  end

  def create
    @task = Task.new(task_params)
    @task.save
    redirect_to tasks_path
  end

  private

  def task_params
    params.require(:task).permit(:title, :content)
  end
end

実装内容に問題が無ければ/tasksに遷移してみましょう。

一旦以下のような表示になっていればOKです!:ok_hand:

image.png

リッチテキストエディタ… どこ?を解決する

実を言うと、この画面は本来以下のような表示になります。

image.png

では何故今こんなにも醜い表示になっているのでしょう…?

類似の条件を漁ってみると、以下のissueで似たような挙動を起こしている方を発見しました。

どうやらAction TextWebpackerはあまり相性が良くない(?)らしく、今回のようにWebpackerでCSS類を管理している場合に、競合してリッチテキストエディタの表示が崩れるという現象が起きるみたいです。

ちなみにTailwind CSSを採用した場合にも起きる模様…。ヒデエな(笑)

解決方法

同issue内で解決方法を提示している神がいました。:sparkles:

まず app/views/layouts/application.html.erb<head>内に以下の1行を追加します。

app/views/layouts/application.html.erb
<%= stylesheet_link_tag "actiontext", "data-turbo-track": "reload" %>

次に app/assets/config/manifest.jsに以下の1行を追加します。

app/assets/config/manifest.js
//= link actiontext.css

それぞれ記述を追加した完成版は以下になります!

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

    <%= stylesheet_link_tag "actiontext", "data-turbo-track": "reload" %>
    <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>
app/assets/config/manifest.js
//= link_tree ../images
//= link_directory ../stylesheets .css
//= link actiontext.css

上記修正した所、以下のように画面が正しく表示されるようになりました!:thumbsup:

image.png

参考

おわりに

いかがでしたでしょうか。

今回はAction TextBootstrapがあまりにも相性が悪すぎる問題と、その解決方法についてご紹介しました。

Action Textは色々な箇所で使い道がありそうですので、今回の内容を元に更なるカスタマイズを施してみるのも良いかもしれませんね!

さて今年のAdvent Calendarもラスト1日になりました…:disappointed_relieved:

ラストはお馴染みGitHubのREADMEをアレンジしてみた!をまとめます!お楽しみに!

58
8
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
58
8