(1)バージョン
ruby
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
rails
Rails 7.1.3.2
その他の環境構築方法については、Rails7 + Ruby3.1 + Bootstrap5 サーバー構築を参照してください
(1)ネットにはRails newするときに、bootstrapを指定するとよいとありますが、これはNode.jsのインストールが必要で、2024/5/9時点でうまく動きません。
$ rails new myapp --css=bootstrap
(2)以下の方法でうまくいきました
①Gemfileに以下を追加
gem 'bootstrap-sass'
gem "sassc-rails"
②app\assets\stylesheetsのapplication.cssをapplication.scssにリネームして、内容をすべて削除して以下を追加
@import 'bootstrap';
③プリコンパイル
$ rails assets:precompile
(3)バージョン5対応
①Gemfileに以下を追加
gem 'bootstrap', '~> 5.1'
gem "sassc-rails"
②app\assets\stylesheetsのapplication.cssをapplication.scssにリネームして、内容をすべて削除して以下を追加
@import 'bootstrap';
③プリコンパイル
$ rails assets:precompile
JQueryのRails7への導入方法は色々あるようですが、今回はRails7で標準のimportmapを使用します。この方法だとNode.jsをインストールしなくてすみます。
(1)JQueryの導入
①JavaScriptの準備を以下のコマンドを入力して行います。importmapでJavaScriptを使用するのに必要なファイル等が作成されます。
$ rails importmap:install
実行結果
apply /root/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/importmap-rails-2.0.1/lib/install/install.rb
Add Importmap include tags in application layout
insert app/views/layouts/application.html.erb
Create application.js module as entrypoint
create app/javascript/application.js
Use vendor/javascript for downloaded pins
create vendor/javascript
create vendor/javascript/.keep
Ensure JavaScript files are in the Sprocket manifest
append app/assets/config/manifest.js
Configure importmap paths in config/importmap.rb
create config/importmap.rb
Copying binstub
create bin/importmap
run bundle install
②以下のコマンドでconfig/importmap.rbにJQueryを指定します。
$ bin/importmap pin jquery
なお今回はRocky9(Linux)で試しましたが、Https通信がエラーになっているようなので、手で以下の内容を入力しました。
エラー内容
/root/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/importmap-rails-2.0.1/lib/importmap/packager.rb:69:in `rescue in post_json':
Unexpected transport error (Net::OpenTimeout: Failed to open TCP connection to api.jspm.io:443 (execution expired)) (Importmap::Packager::HTTPError)
config/importmap.rb
pin "application", preload: true
pin "jquery", to: "https://ga.jspm.io/npm:jquery@3.7.1/dist/jquery.js"
③JSファイルで使用できるようにapp/javascript/application.jsに以下を指定します。
import jquery from "jquery"
window.$ = jquery
(2)自作のJQueryを使用する
①/app/javascript配下にcustomフォルダを作成します(名前は任意)
②/app/javascript/customフォルダに自作のJSファイルを作成します
例)test.js
// フォームロード時の処理
$(window).on('load', function () {
alert("フォームロード");
}); // フォームロード時の処理終了
③/app/views/layouts/application.html.erbに以下の行を追加します(:jsという名前は任意)
<!DOCTYPE html>
<html>
<head>
<title>TestPg4
<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_importmap_tags %>
<!-- 追加開始 -->
<%= yield (:js) %>
<!-- 追加終了 -->
</head>
<body>
<%= yield %>
</body>
</html>
④上記jsを導入したいViewに以下のように追加します
<p style="color: green"><%= notice %></p>
<h1>Webmemos</h1>
<div id="webmemos">
<% @webmemos.each do |webmemo| %>
<%= render webmemo %>
<p>
<%= link_to "Show this webmemo", webmemo %>
</p>
<% end %>
</div>
<%= link_to "New webmemo", new_webmemo_path %>
<!-- 追加開始 -->
<% content_for :js do %>
<%= javascript_import_module_tag "custom/test" %>
<% end %>
<!-- 追加終了 -->
①config/importmap.rbに以下の2行を追加します
# 最終行に次の2行を追加
pin "vue", to: "https://ga.jspm.io/npm:vue@3.2.45/dist/vue.esm-browser.js", preload: true
pin_all_from "app/javascript/components", under: "components"
②app/javascript/componentsにvue.jsのファイルを配置します(template部分はRailsのscaffoldで作成したコードを使用し、修正)
例)work_msts_index.js
import * as Vue from "vue"
const WorkMstsIndex = {
template: `
<div class="card border-info table-responsive">
<table class="table table-striped table-bordered table-hover table-sm">
<thead>
<tr class="bg-primary text-white">
<td width="100px" class="bg-primary text-white"><label>作業コード</label></td>
<td width="100px" class="bg-primary text-white"><label>作業名</label></td>
<td width="100px" class="bg-primary text-white"><label>備考</label></td>
<td width="50px" class="bg-primary text-white"></td>
<td width="50px" class="bg-primary text-white"></td>
<td width="50px" class="bg-primary text-white"></td>
</tr>
</thead>
<!-- 表本体 -->
<tbody>
<tr v-for="data in dataes">
<td>{{data.work_cd}}</td>
<td>{{data.name}}</td>
<td>{{data.note}}</td>
<td class="fcenter">
<a class="btn btn-primary btn-sm text-white" :href="'/work_msts/' + data.id">
<i class="bi bi-info-circle-fill" aria-hidden="true"></i> 詳細
</a>
</td>
<td class="fcenter">
<form data-turbo-confirm="本当に削除してよろしいですか?" class="button_to" method="post" :action="'/work_msts/' + data.id">
<input type="hidden" name="_method" value="delete" autocomplete="off" />
<button class="btn btn-danger btn-sm" type="submit">
<i class="bi bi-trash" aria-hidden="true"></i> 削除
</button>
<input type="hidden" name="authenticity_token" value="iPZlKdNww4uxtyXxF4KXHx8_ZyxA3ZLlekhzv_STHoyvOpibSi645D15p9KL60pi6MbL35Tm_ac_MSK6zjugtA" autocomplete="off" />
</form>
</td>
<td class="fcenter">
<a class="btn btn-primary btn-sm" :href="'/work_msts/' + data.id + '/edit'">
<i class="bi bi-pencil-square" aria-hidden="true"></i> 編集
</a>
</td>
</tr>
</tbody>
</table>
</div>
`,
data(){
return {
dataes: [],
selected: 0,
data: {}
}
},
created: function(){
this.getData();
},
methods: {
getData() {
fetch('/work_msts.json')
.then(response => response.json())
.then(data => {
this.dataes = data,
console.log(data)
})
},
}
};
const app = Vue.createApp({
components: {
'work_msts_index': WorkMstsIndex,
},
});
app.mount('#work_msts_index');
③app/javascript/application.jsに上記で作成したjsファイルを指定します
import "./components/work_msts_index"
④app/viewsのviewファイルにvue.jsがtemplateを展開するコードを記述します
例)app/views/work_msts/index.html.erb(比較のため、前半部分はRailsのscaffoldで作成したコードを記述しています)
fetch('/work_msts.json')はviews/work_msts/index.json.jbuilderでデータを取得しています。その取得したデータをjs内のdataesに格納して、そのあとtemplateでhtmlに展開しています
<!-- RailsのScaffoldで作成開始 -->
<div class="container">
<div class="content-title">
<h3><span class="title-style"><%= label :work_mst, :table_name %><label>一覧</label></span></h3>
</div>
<!-- メッセージ領域 -->
<%= render partial: 'shared/message' %>
<!-- ボタン領域 -->
<div class="align-right padding-bottom5">
<%= link_to new_work_mst_path, class: "btn btn-primary" do %>
<i class="bi bi-plus-lg" aria-hidden="true"></i> 新規
<% end %>
<%= link_to menu_index_path, class: "btn btn-success" do %>
<i class="bi bi-x-lg" aria-hidden="true"></i> 戻る
<% end %>
</div>
<!-- 表見出し -->
<div class="card border-info table-responsive">
<table class="table table-striped table-bordered table-hover table-sm">
<thead>
<tr class="bg-primary text-white">
<td width="100px" class="bg-primary text-white"><%= label :work_mst, :work_cd %></td>
<td width="100px" class="bg-primary text-white"><%= label :work_mst, :name %></td>
<td width="100px" class="bg-primary text-white"><%= label :work_mst, :note %></td>
<td width="50px" class="bg-primary text-white"></td>
<td width="50px" class="bg-primary text-white"></td>
<td width="50px" class="bg-primary text-white"></td>
</tr>
</thead>
<!-- 表本体 -->
<% @work_msts.each do |work_mst| %>
<tr>
<td><%= work_mst.work_cd %></td>
<td><%= work_mst.name %></td>
<td><%= work_mst.note %></td>
<td class="fcenter">
<%= link_to work_mst, class: "btn btn-primary btn-sm" do %>
<i class="bi bi-info-circle-fill" aria-hidden="true"></i> 詳細
<% end %>
</td>
<td class="fcenter">
<%= button_to work_mst, {method: :delete, form: {data: {turbo_confirm: '本当に削除してよろしいですか?' }},class: "btn btn-danger btn-sm"} do %>
<i class="bi bi-trash" aria-hidden="true"></i> 削除
<% end %>
</td>
<td class="fcenter">
<%= link_to edit_work_mst_path(work_mst), class: "btn btn-primary btn-sm" do %>
<i class="bi bi-pencil-square" aria-hidden="true"></i> 編集
<% end %>
</td>
</tr>
<% end %>
</table>
</div>
<!--ページネート-->
<div class="pagenate">
<ul class="pagenation justify-content-center">
<%= will_paginate(@work_msts, previous_label: '前へ', next_label: '次へ', renderer: WillPaginate::ActionView::BootstrapLinkRenderer) %>
</ul>
</div>
<!-- RailsのScaffoldで作成終了 -->
<!-- Vue.js追加開始 -->
<div id="work_msts_index">
<work_msts_index></work_msts_index>
</div>
<!-- Vue.js追加終了 -->
</div>
⑤実行結果
上の表示が従来のRailsで表示したもので、下の表示がvue.jsで表示したものになります