Rails7とBootstrap

一般に、HTMLは文書の構造を表し、CSSはその体裁(見栄え)を表します。 Railsは最終的にCSSを含むHTML文書を出力するので、この2つについての理解が必須です。 この記事ではとくにCSSの人気ライブラリであるBootstrapを紹介します。 BootstrapはJavascriptも含んでいます。

インストール

RailsとBootstrapの両方とも開発スピードが速いです。 そのため両者を組み合わせてインストールするのは、なかなか難しいものがあります。

  • インターネット情報は古いものが多い
  • 最新のバージョンの組み合わせに対する情報が少ない

今回ここで紹介するのはRails7とBootstrap5の組み合わせで「rails new」コマンドに「-c bootstrap」または「--css=bootstrap」オプションをつける方法です。 自分にとっても新しい方法なので、この記事が正しいと保証することができません。 ひとつの体験談として、また数ある情報のひとつとしてお考えいただきたいと思います。 また、この記事に基づいて行ったことから発生する問題に対して何ら保証するものではありませんので、自己責任でお願いします。

(補足)古いバージョンのrailsではgemを使っていました。 たとえば、bootstrapbootstrap-sassなどです。 Rails7でもそれらを使うことは可能だと思います。 ただし、bootstrap-sassはBootstrap3にしか対応していません。 rails7では、newコマンドでBootstrap5の導入が簡単にできるようになりました。 ここで用いた方法以外にCDNを使う方法も可能だと思います(検証不十分)。 CDNはBootstrapで推奨されている方法で、詳しくはBootstrapのサイトを見てください。

私のPC環境は「Ubuntu 22.04」です。

rails new word_book_rails -c bootstrapを行うと、エラーが出ました。

error @hotwired/turbo@7.2.2: The engine "node" is incompatible with this module. Expected version ">= 14". Got "12.22.9"
error Found incompatible module.

Ubuntu22.04の現在のnodejsのバージョンが12.22.9なので、それが古いというエラーだと思われます。 (注:現在のUbuntu最新版は22.10になりました[2022/11/1]。そのnodejsパッケージのバージョンは18.7.0なので、以下のnodejsの最新版インストールは必要ありません)。 nodejsの新しいバージョンをインストールする情報がnodesource/distributionsにあります。 エラーメッセージではバージョン14以上が必要となっていますが、最新が18なので、それをインストールしてみます。 nodesource/distributionsのREADME.mdの情報によると、次のコマンドを実行すればよいとのことです。

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - &&\
sudo apt-get install -y nodejs

実行したところなぜかエラーになり、その後sudo apt autoremovesudo apt remove nodejssudo apt install nodejsしたところ最新版がインストールできました。 エラーが気になりますが、一応次のようになっています。

$ node --version
v18.11.0

word_book_railsフォルダを削除して、再度newコマンドで作成します。

$ rm -rf word_book_rails
$ rails new word_book_rails -c bootstrap

たくさんのメッセージが現れ、数多くの作業が行われていることが感じられます。 途中で

npm WARN set-script set-script is deprecated, use `npm pkg set scripts.scriptname="cmd" instead.

という警告が出ますが、エラーではないので問題ないでしょう。 また、次のようなメッセージも出ます。

File unchanged! The supplied flag value not found!  app/assets/config/manifest.js

これがエラーなのか、警告なのか、あるいは問題のない状況なのかは良く分かりませんでした。 しかし、フォルダ内を見渡したところ、Bootstrapはインストールできているので、このまま次の作業に入りたいと思います。

Bootstrapとは?

BootstrapはCSSとJavascriptのライブラリです。 これを使うことによって、ウェブの見栄えを美しくしたり、プルダウンメニューのような動的画面を簡単に作ることができます。 これをBootstrap無しで一から作るとしたら、膨大な時間がかかります。 Bootstrapは本当に神様のようなライブラリです(しかも無料)。 また、CSSやJavascriptをよく知らなくても使えるので、学習コストを大幅に下げることができます。

具体的な例はBootstrapのウェブサイトを参照してください。 例えば「Components」の「Buttons」を見ると、サンプルとコードがあります。

Bootstrap=>ドキュメント=>Components=>Buttons

<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-secondary">Secondary</button>
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-danger">Danger</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-light">Light</button>
<button type="button" class="btn btn-dark">Dark</button>

<button type="button" class="btn btn-link">Link</button>

サンプルのような色、形のボタンを作るには、対応するコードを書けば(コピペすれば)良いだけです。

また、「Layout」の「Containers」はレスポンシブデザイン(ディスプレイ画面の大きさに合わせて描画領域を自動的に変更する)のコンテナ(箱)です。 bodyタグの内側を<div class="container"></div>で囲めば、その内容を画面サイズに合うようにサイズ調整してくれます。

この他にも有用な機能が数多くあるので、良く見てください。

Bootstrapの使用例

今回はBootstrapのコンテナ、コラムとナビゲーションバーを使おうと思います。

作成する単語帳のウェブサイトを「Wordbookサイト」または単に「Wordbook」と呼ぶことにします。

コンテナ

Wordbookのすべてのビュー(画面)はレスポンシブデザインになるように、コンテナの中にいれます。 すべてのビューはapplication.html.erbの中に埋め込まれるので、このファイルにコンテナを設定します。

app/views/layouts/application.html.erbをエディタで開き、ボディタグの中身を次のように変更します。

<body>
  <div class="container">
    <div class="col-sm-10 col-lg-8 col-xl-6 mx-auto">
      <%= yield %>
    </div>
  </div>
</body>

それぞれのビューはyieldのところに埋め込まれるので、すべてのビューがclass="container"のdivタグに囲まれ、レスポンシブになります。

containerは、大きい画面に対して幅を狭くして見やすくしているのですが、それでもWordbookでは幅が広すぎます。 そこで、更に幅の調整をしているのが<div class="col-sm-10 col-lg-8 col-xl-6 mx-auto">です。

Bootstrapではcontainerで設定された幅を12等分し、そのひとつひとつをカラム(column 列)と呼びます。 col-1からcol-12で1カラム分から12カラム分の幅を設定できます。 また、col-sm-10のように、sm(smallサイズ以上の画面)をつけて、画面サイズに限定したカラムの設定ができます。 なお、画面サイズを区切るブレークポイント6個定義されています。

ブレークポイント クラスの接中辞 画面幅の範囲 コンテナの幅
X-Small なし <576px 100%
Small sm ≥576px 540px
Medium md ≥768px 720px
Large lg ≥992px 960px
Extra large xl ≥1200px 1140px
Extra extra large xxl ≥1400px 1320px

では、<div class="col-sm-10 col-lg-8 col-xl-6 mx-auto">の内容を詳しく見ていきましょう。

  • col-sm-10 => smallサイズ以上の画面では幅を10カラム分とる
  • col-lg-8 => largeサイズ以上の画面では幅を8カラム分とる
  • col-xl-6 => extra largeサイズ以上の画面では幅を6カラム分とる
  • mx-auto => mはマージン、xは左右、autoは自動計算で大きさを決める、という意味。 この場合、カラムで内部の幅がきまるので、containerの幅からそれを引いた残りが左右マージンの合計になる。 左右ともautoに指定されているので、この値を半分にした値が左右それぞれのマージンに設定される。 その結果、センタリングと同じ効果が得られる。 (W3C CSSヒントとトリック参照)

画面サイズごとのカラム数は次のように成ります。

画面サイズ カラム数
xs 12
sm 10
md 10
lg 8
xl 6
xxl 6

例えば、xsは最も小さい画面(スマホ画面など)で、12カラム、すなわちコンテナの全幅を使用します。 また、最も大きい画面のxxl(幅1400px以上)で、6カラム、すなわちコンテナの半分の幅になります。

カラムについてはStandalone Column Classesを参照してください。

ナビゲーションバーとパーシャル

Wordbookはナビゲーションバーを常に表示します。 ナビゲーションバーには、append、change、delete、searchなどのメニュー(実際にはリンク)を設定します。

ナビゲーションバーはパーシャルと呼ばれるファイルに記述します。 パーシャルはビューから呼ばれ、そこに埋め込まれるファイルです。 プログラムのサブルーチンに似ています。

例えば、

<%= render "abc" =>

とビューの中で書かれた部分はapp/views/words/_abc.html.erbの内容で置きかえられます。 ファイル名の先頭にはアンダースコア(_)がつくことに注意してください。

ナビゲーションバーのサンプルが、Bootstrapのウェブの「Components=>Navbar」にあります。 そのコードをコピペしてから改変します。 以下にパーシャルapp/views/words/_navbar.html.erbの内容を示します。

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" href="/">Wordbook</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link" href="/words/append">Append</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="/words/change">Change</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="/words/delete">Delete</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="/words/search">Search</a>
        </li>
    </div>
  </div>
</nav>

変更箇所は、3行目のブランド名をWordbookに、それから9行目から20行目までの項目をAppendからSearchにしたところです。

  • Append=>単語を追加する画面に遷移する
  • Change=>単語を変更する画面に遷移する
  • Delete=>単語を削除する画面に遷移する
  • Search=>単語を検索する画面に遷移する

このパーシャルはレイアウトから呼ばれるようにします。 そのことにより、いつでもナビゲーションバーが現れるようになります。

レイアウトには、この他にフラッシュのパーシャルも読み込ませますが、フラッシュについては別の記事で説明します。 最終的に、レイアウトは次のようになります。

<!DOCTYPE html>
<html>
  <head>
    <title>WordBookRails</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-turbo-track": "reload", defer: true %>
  </head>

  <body>
    <div class="container">
      <div class="col-sm-10 col-lg-8 col-xl-6 mx-auto">
        <%= render "navbar" %>
        <%= render "flash" %>
        <%= yield %>
      </div>
    </div>
  </body>
</html>

indexビュー

indexのビューは見出しと順序なしリストから構成されます。 リストの項目はナビゲーションバーの説明です。

<h1 class="text-center">単語帳</h1>
<h5 class="my-2">単語帳の使い方</h5>
<ul class="list-group">
  <li class="list-group-item">Wordbook: 初期画面に戻ります</li>
  <li class="list-group-item">Append: 単語を追加します</li>
  <li class="list-group-item">Change: 登録済み単語を変更します</li>
  <li class="list-group-item">Delete: 単語を削除します</li>
  <li class="list-group-item">Search: 単語を検索しマッチした単語を表示します</li>
</ul>

動作確認

Bootstrapの効果を確認するために、初期画面のみ実装してみます。 ルーティング、コントローラ、ビューの3つが必要です。

config/routers.rbroot "words#index"の1行を加えます。

Rails.application.routes.draw do
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
  # root "articles#index"
  root "words#index"
end

コントローラWordsを作ります。 アクションは初期画面がindexで、AppendからSearchまではそれぞれ同名小文字にします。 railsのgenerateコマンドで作成します。

$ bundle exec rails generate controller Words index append change delete search
      create  app/controllers/words_controller.rb
       route  get 'words/index'
              get 'words/append'
              get 'words/change'
              get 'words/delete'
              get 'words/search'
      invoke  erb
      create    app/views/words
      create    app/views/words/index.html.erb
      create    app/views/words/append.html.erb
      create    app/views/words/change.html.erb
      create    app/views/words/delete.html.erb
      create    app/views/words/search.html.erb
      invoke  test_unit
      create    test/controllers/words_controller_test.rb
      invoke  helper
      create    app/helpers/words_helper.rb
      invoke    test_unit

コントローラの内容変更は今のところありません。

ビューを作ります。

以上の準備をしたら、railsでサーバを動作させてブラウザで画面確認します。 今回はbundle exec rails serverを使わずに./bin/devを使います。 これは、前者ではJavascriptが動作しないためです。 Rails Guideの「Working with JavaScript in Rails」の「2 Adding NPM Packages with JavaScript Bundlers」に./bin/devのことが書かれています。

$ ./bin/dev
21:03:34 web.1  | started with pid 50151
... ... ...
... ... ...
21:03:35 web.1  | * Listening on http://127.0.0.1:3000
21:03:35 web.1  | * Listening on http://[::1]:3000
21:03:35 web.1  | Use Ctrl-C to stop
21:03:36 css.1  | Sass is watching for changes. Press Ctrl-C to stop.
21:03:36 css.1  | 

ここでブラウザでhttp://localhost:3000を見てみます。

Word-indexの画面

コンテンツの幅がコンテナよりもかなり小さくなっていることが分かると思います。 また、上にナビゲーションバーも表示されています。

ブラウザがChromeであれば、スマホ画面でどうなるかを確かめることができます。 右上の3つドットが縦に並んでいるアイコンをクリック=>その他のツール=>デベロッパーツール、と選択します。 中央上に画面サイズ設定のメニューがあります。 そこで、IphoneSEのサイズを選んだのが次の図になります。

iPhoneSEサイズのWord-index画面

スマホ画面いっぱいにコンテンツが表示されていて、レスポンシブ・デザインが効いていることがわかります。 また、ナビゲーションバーも変化しています。 ハンバーガーメニューが右上に現れ、それをクリックするとドロップダウンメニューの中にAppendからSearchまでのメニューが入っています。 このような動的な動きはBootstrapのJavascriptがやっています。

まとめ

Bootstrapを用いたので労せずメニューやレスポンシブデザインを作ることができました。 BootstrapはRailsに限らず、一般のウェブサイト制作に適用することができます。 どんどん使ってみてください。

2023

単項マイナスと構文解析

1 minute read

単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合

Raccライブラリと構文解析

3 minute read

パーサ・ジェネレータとは 少し複雑な文法 四則(加減乗除)計算のBNF Racc で実装 クラス定義、BNFの記述部分 ヘッダー、インナー、フッター コンパイルと実行 演算子の優先順位と結合における左右の優先順位 まとめ

StrScanライブラリと字句解析

less than 1 minute read

StrScanライブラリのドキュメント 字句解析とは StrScanライブラリ StrScanライブラリを使った字句解析 実例

Gem

1 minute read

lbtというgemを作って公開してみた lbtはどんなgemか ファイルの配置 lbt.gemspec Rakefile gemのビルド RubyGems.orgへのアップロード 補足・・rake/gempackagetaskサブライブラリについて

Encoding

1 minute read

文字列のエンコーディングに頭を悩ませることはほとんどなくなりました。 なぜなら、どのアプリ、システムもUTF-8を使うようになったからです。 Rubyでもエンコーディングの問題が起こることはまず無いでしょう。 ですが、今回はエンコーディングの考え方を整理してみたいと思います。

Thread

less than 1 minute read

Fiberを書いたときから、次はスレッドを書こうと思っていましたが、時間がかかってしまいました。 その理由は、期待したとおりのスレッドの効果がなかったためです。 今回はそのことを書きますが、これはRubyのスレッドの抱えている問題なのか、自分のやり方が悪いのかははっきりしていません。

Fiber

1 minute read

Fiberは「ノンプリエンプティブな軽量スレッド」とRubyのマニュアルに記載されています。

RDoc

less than 1 minute read

今回はRubyプログラムから自動的にドキュメントを作成するRDocについて書きたいと思います。 私はこのことについて、エキスパートではありません。 この記事も、初心者の体験談だと考えてください。

Back to Top ↑

2022

Ruby/GTK4

5 minute read

Ruby/Gtkの記事を先日書いたときに、「これはかなり使える」という手応えを感じたので、WordBook(Railsで作った単語帳プログラム)のGTK 4版を作りました。 プログラムは「徒然なるままにRuby」のGitHubレポジトリに置いてあります。 レポジトリをダウンロードし、ディレクトリ_example/...

Shoes – Rubyとグラフィック

5 minute read

Rubyはグラフィックについて弱い印象があります。 しかし、グラフィックはデバイスに関することなので、言語そのものには直接の関係はないはずで、あるとすればライブラリです。 今後グラフィック関係のgemが開発されることに期待しましょう。

Rails7 テスト

5 minute read

前回作ったWordbook(リソースフル)のテストを書いてみます。 RailsのテストはminitestをRails用に拡張したものです。

Rails7 モデルとデータベース

2 minute read

今回はRailsにおけるデータの作成と保存、そして変更について説明します。 そのベースになるモデルとデータベースの話から始め、appendとchangeの動作について詳しく説明します。

Rails7とBootstrap

3 minute read

一般に、HTMLは文書の構造を表し、CSSはその体裁(見栄え)を表します。 Railsは最終的にCSSを含むHTML文書を出力するので、この2つについての理解が必須です。 この記事ではとくにCSSの人気ライブラリであるBootstrapを紹介します。 BootstrapはJavascriptも含んでいます。

Rails7のインストール

2 minute read

Rubyの最も人気のあるアプリケーションであるRuby on Railsを取り上げようと思い、書き始めました。 予想してはいましたが、相当な分量になってしまいました。 そのため、何回かに分けて記事にすることにします。 また、対象となる読者のレベルをどうしようかと考えましたが、「徒然Ruby」が基礎的な内容から始ま...

GemとBundler

1 minute read

Rubyのライブラリ管理システムのRubygemsとコマンドgemおよびbundlerについて説明します。

minitest(3)モックの詳細

1 minute read

minitestについて連続して2回書いてきました。 「minitestはドキュメントが少ない」という人がいますが、私も同感です。 例えば、モックとスタブの説明も少ないです。 そこで、今回はmock.rbのソースコードを参考に、モックの私的ドキュメントを書いてみました。 あくまで私個人の考えであり、minites...

minitest(1)テストとは

2 minute read

アプリ作成の記事でminitestを使いました。 今回はminitestについて、また一般にテストについて、私の考えを書こうと思います。

public、private、protected

2 minute read

今回はメソッドの呼び出し制限ついて説明します。 呼び出し制限にはpublic、private、protectedの3つがあります。

アプリ制作、インストール、テスト

1 minute read

2023/10/29 追記:この記事は新しく書き直しました。 古い記事で使っていたGitHubのCalcが大幅にアップデートされたためです。 そこで、この記事に合うようなプログラムsimple_calcを新たに作りました。 このプログラムは本レポジトリの_example/simple_calcにあります。

case文

2 minute read

if〜elsif〜・・・〜else〜endは皆さん良く使うでしょうか? これは場合分けで良く使われる方法です。 これと同様の制御構造にcase文があります。 Cのswitch文に似ていますが、より強力な機能を持っています。 if-else-endよりも高い能力があるといえます。

Lambda

2 minute read

Procオブジェクトを生成するメソッドlambdaについて説明します。

Proc オブジェクト

2 minute read

今回はブロックを一般化したオブジェクトProcを説明します。

モジュール

1 minute read

モジュールには名前空間とミックスイン(Mix-in)の2つの機能があります。 ここではミックスインについて説明します。

Kernelモジュール

less than 1 minute read

Kernelモジュールのメソッドはどこでも使うことができます。 そのメソッドの中には便利で有用なものが多いです。

便利なメソッド

1 minute read

ここでは私が便利だと思ったメソッドを紹介します。

文字列と正規表現

3 minute read

文字列は最も使うオブジェクトのひとつです。 特にウェブ・アプリケーションでは、コンテンツだけでなくHTMLのタグやCSSを含めすべてが文字列です。 Rubyは文字列オブジェクトのメソッドが充実しており、またパターンマッチのための正規表現も充実しています。

配列

2 minute read

配列は、どのプログラミング言語にもあると思います。 複数の要素を一括して扱うことができるのが配列です。 Rubyの配列はメソッドが充実しているので、プログラムを効率的、機能的に書くのに役立ちます。

トップレベルのメソッド

1 minute read

今回はメソッド定義です。 メソッド定義はRubyの核心ですが、今回はトップレベルに限って説明します。 この限定によって、内容はかなり易しくなっています。

ブロックとイテレータ

less than 1 minute read

ブロックはRubyの特長です。 ブロックのおかげで記述が非常にすっきりと分かりやすくなります。 今回はブロックをイテレータの本体として使う方法を説明します。

整数

less than 1 minute read

ここではRubyの最も基本的なオブジェクトである整数について説明します。

Hello world

less than 1 minute read

「徒然なるままに」をネットで調べてみると、「することもなく、手持無沙汰なのにまかせてという意味」とありました。 まさに、自分の現状を言い当てた言葉。 しかも、ブログに書くネタもなかなか思いつかない日々。

Back to Top ↑