跳至主要内容

[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 -%>

資料來源