[Rails] Rails with Stimulus 起手式
確認 Ruby 環境與 Rails 版本
# 建立並確定 Ruby 版本
$ rvm list known # 找出最新版本的 Ruby
$ rvm install 2.5 # 安裝特定版本的 Ruby
$ rvm --default use 2.5 # 使用特定版本的 Ruby 並設為預設值
# 確認 RubyGems 版本和套件版本
$ gem update --system # 若版本不夠新,則升級 RubyGems 的版本(不是 gems)
$ gem list | grep rails # 確認當前 Rails 版本
$ gem update rails # 若版本不夠新,則將 Rails 更新至最新版
建立 Rails + Stimulus 專案
建立專案
# 建立 Rails + Stimulus 專案
$ rails new <project_name> --webpack=stimulus --database=postgresql --skip-coffee --skip-test
$ cd <project_name>
$ rails db:migrate
測試使用 Stimulus
# 測試 Rails + Stimulus 能否使用
$ rails g controller pages index # http://localhost:3000/pages/index
將 javascript/packs/application.js
掛入 layout 中:
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
...
<%= javascript_pack_tag 'application' %> <!-- 將 webpack entry 掛入 -->
...
</head>
<body>
<%= yield %>
</body>
</html>
把內建的範例複製到 app/views/pages/index
:
<!-- app/views/pages/index.html.erb -->
<div data-controller="hello">
<h1 data-target="hello.output"></h1>
</div>
若於頁面上看到 Hello, Stimulus!! 即表示已完成 Stimulus 安裝。
設定 CSS 檔
# Using webpacker for stylesheets
$ mkdir app/javascript/stylesheets
$ touch app/javascript/stylesheets/application.scss
$ touch app/javascript/stylesheets/_variables.scss
Import CSS file in app/javascript/pack/application.js
:
// layout file, like app/views/layouts/application.html.erb
import 'stylesheets/application';
Import CSS file by stylesheet_pack_tag
in app/views/layout/application.html.erb
:
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
...
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
...
</head>
</html>
現在你可以在開始撰寫 CSS 了:
// app/javascript/stylesheets/application.scss
@import 'variables';
// app/javascript/stylesheets/_variables.scss
$colors: (
major: #00d252,
minor: #2f3b59,
);
安裝 Bootstrap
# https://getbootstrap.com/docs/4.1/getting-started/webpack/
$ yarn add jquery popper.js bootstrap
app/javascript/stylesheets/application.scss
// app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';
...
app/javascript/pack/application.js
// app/javascript/pack/application.js
import 'bootstrap'
...
Add configuration to config/webpack/environment.js
// config/webpack/environment.js
const { environment } = require('@rails/webpacker');
const webpack = require('webpack');
/**
* Automatically load modules instead of having to import or require them everywhere.
* Support by webpack. To get more information:
*
* https://webpack.js.org/plugins/provide-plugin/
* http://j.mp/2JzG1Dm
*/
environment.plugins.prepend(
'Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
jquery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default'],
}),
);
module.exports = environment;
測試 Bootstrap 的使用
在 app/views/pages/index.html.erb
中使用 Bootstrap 模板:
<!-- app/views/pages/index.html.erb -->
<h1>Pages#index</h1>
<p>Find me in app/views/pages/index.html.erb</p>
<div data-controller="hello">
<h1 data-target="hello.output"></h1>
<div class="alert alert-primary" role="alert">
This is a primary alert—check it out!
</div>
<div class="alert alert-secondary" role="alert">
This is a secondary alert—check it out!
</div>
<button type="button" class="btn btn-secondary" data-toggle="tooltip" data-placement="top" title="Tooltip on top">
Tooltip on top
</button>
</div>
此時因為 jQuery 並沒有載入到全域,因此要在 app/javascript/
內才可以使用 jQuery:
// app/javascript/packs/application.js
import 'bootstrap';
import 'stylesheets/application';
import { Application } from 'stimulus';
import { definitionsFromContext } from 'stimulus/webpack-helpers';
const application = Application.start();
const context = require.context('controllers', true, /.js$/);
application.load(definitionsFromContext(context));
$(function () {
$('[data-toggle="tooltip"]').tooltip();
});
若有看到 Bootstrap alert 樣式,另外 tooltip 能夠使用的話,即表示正常運作。
其他
將 jQuery 載入到全域
在上面的範例中,並沒有將 jQuery 載入到全域,若有需要在全域的環境下使用 jQuery(例如在 template 中透過 <script>
使用),則需要:
# https://webpack.js.org/loaders/expose-loader/
$ yarn add expose-loader -D
Add configuration to config/webpack/environment.js:
// config/webpack/environment.js
environment.loaders.append('expose', {
test: require.resolve('jquery'),
use: [
{
loader: 'expose-loader',
options: '$',
},
],
});
如此將可以在全域(window)底下使用到 jQuery。
More example: clipboard_controller.js
$ touch app/javascript/controllers/clipboard_controller.js
Provide an example of clipboard controller in app/views/pages/index.html.erb:
<!-- app/views/pages/index.html.erb -->
<div data-controller="clipboard">
PIN:
<input type="text" value="1234" data-target="clipboard.source" readonly>
<button data-action="click->clipboard#copy" class="clipboard-button">Copy to Clipboard</button>
</div>
Add app/javascript/controllers/clipboard_controller.js
// app/javascript/controllers/clipboard_controller.js
import { Controller } from 'stimulus';
export default class extends Controller {
static targets = ['source'];
connect() {
if (document.queryCommandSupported('copy')) {
console.log('clipboard-supported');
this.element.classList.add('clipboard--supported');
}
}
copy() {
this.sourceTarget.select();
document.execCommand('copy');
console.log(`text "${this.sourceTarget.value}" has been copied into your clipboard`);
}
}
讓透過 generator 產生的 Model 有預設內容
$ mkdir -p lib/templates/active_record/model
$ touch lib/templates/active_record/model/model.rb
lib/templates/active_record/model/model.rb
:
<!-- lib/templates/active_record/model/model.rb -->
<% module_namespacing do -%>
class <%= class_name %> < <%= parent_class_name.classify %>
# scope macros
# Concerns macros
# Constants
# Attributes related macros
<% if attributes.any?(&:password_digest?) -%>
has_secure_password
<% end -%>
# association macros
<% attributes.select(&:reference?).each do |attribute| -%>
belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %>
<% end -%>
# validation macros
# callbacks
# other
private
# callback methods
end
<% end -%>
資料來源
- Rails 5.2 with webpacker, bootstrap, stimulus starter @ Andyyou
- Stimulus 手冊 - 繁體中文版 @ Andyyou