SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Railsによるクライアントサイド開発入門

Rails 7で簡単にSPA開発! Turbo StreamsとJavaScript利用を支援するStimulus

Railsによるクライアントサイド開発入門 第6回

  • X ポスト
  • このエントリーをはてなブックマークに追加

TurboでのJavaScriptの利用を支援するStimulus

 StimulusはTurboの機能を補完する位置付けのライブラリです。Turboは便利で高機能ですが、より細かな振る舞いを実装するには、やはりJavaScriptのコーディングが必要になってきます。このようなときにStimulusは一定の枠組みを導入してくれますので、JavaScriptの濫用という起きがちな問題を回避できるというメリットがあります。

 ここからは、Stimulusを使ってアプリケーションに入力検証機能を付加していきます。検証機能はRails自身が備えていますが、これをフォームの送信前に行ってみようというわけです。検証内容は「フィールドが埋められているか?」とし、フィールドを埋めないと[Create new Word]ボタンをクリックできないものとします(図6)。

図6 Stimulusによるボタンの制御
図6 Stimulusによるボタンの制御

Stimulusの基本的な動作

 Stimulusは、既存のHTMLに対しての処理を主な目的としています。対象となるHTML要素は「ターゲット」として指定し、処理の内容を「アクション」に定義します。両者は「コントローラ」によってひも付けます。Hotwireを有効にしてアプリケーションを作成すると、app/javascript/controllersフォルダに、Stimulusのコントローラファイルhello_controller.jsがリストのように作成されています。命名規則はRailsと同様で、Helloコントローラのためのファイルということになります。

リスト app/javascript/controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    this.element.textContent = "Hello World!"
  }
}

 ここにはコールバック関数connect()が定義されているだけです。ただ、コントローラファイルはあっても、ターゲットがない場合には、何の動きも発生しません。そこで、アプリケーションの一覧ページに、以下のようにdiv要素を追加します。

リスト app/views/words/index.html.erb
<h1>Words</h1>
<div data-controller="hello"></div>	追加
<div id="words">
…略…

 ここで一覧ページを表示させると、図7のように「Hello World!」と表示されるのが分かります。これは、hello_controller.jsのconnect関数の処理内容そのものです。

図7 StimulusでHello World!
図7 StimulusでHello World!

 ここでconnectとは、HTML要素とコントローラがひも付いた(接続された)時点で呼ばれることを意味しています。index.html.erbに追加したdiv要素にはdata-controller属性が付加されており、これがdiv要素とHelloコントローラをひも付けているのです。同様にdata-target属性、data-action属性がありますが、これらについてはサンプルを紹介しながら随時取り上げることにします。

 ここで、index.html.erbに追加したdiv要素は不要になるので、削除するかコメントアウトして無効にしておいてください。

コントローラを作成する

 stimulus-railsによって、Stimulusのコントローラはrails generate stimulusコマンドで作成できます。今回は入力内容の検証なので、Validateコントローラとします。

% rails generate stimulus validate
      create  app/javascript/controllers/validate_controller.js

 これで、app/javascript/controllers/validate_controller.jsが作成されます。このファイルには、Stimulusコントローラに必要な基本的な記述がすでに行われています。なお、RailsのデフォルトではImport Mapsが使われますので、app/javascript/controllers以下のスクリプトは自動的にインポートされます。

コントローラを設定する

 コントローラを設定します。フォームの検証になるので、app/views/words/_form.html.erbのform_withメソッドにコントローラのためのdata属性を指定します。

リスト app/views/words/index.html.erb
<%= form_with(model: word, data: { controller: 'validate' }) do |form| %>
…略…

 この指定により、form要素に「data-controller: 'validate'」属性が付加されて、フォーム内でValidateコントローラが使用できるようになります。

ターゲットとアクションを設定する

 操作の対象となるターゲット(コントローラから参照する際の名前)と、必要な場合にはアクション(コントローラのメソッド名)を設定します。操作とは、更新はもちろんのこと取得も対象になるので、ボタンと2つのテキスト入力フィールドをターゲットに設定します。同じくapp/views/words/_form.html.erbの3つのコントロールにターゲットのdata属性を設定します。

リスト app/views/words/_form.html.erb
…略…
<div>
  <%= form.label :japanese, style: "display: block" %>
  <%= form.text_field :japanese, data: { validate_target: 'japanese', 
    action: 'input->validate#japanese' } %>		(1)
</div>
<div>
  <%= form.label :english, style: "display: block" %>
  <%= form.text_field :english, data: { validate_target: 'english', 
    action: 'input->validate#english' } %>		(2)
</div>
<div>
  <%= form.submit data: { validate_target: 'button'} %>	(3)
</div>

 設定内容をまとめると表のようになります。

表 フォーム要素へのターゲットとアクションの設定
フォーム要素 ターゲット アクション
(1)テキスト入力フィールド(japanese) japanese input->validate#japanese
(2)テキスト入力フィールド(english) english input->validate#english
(3)ボタン button

 「data: { validate_target: 'japanese'…」の指定で、data-validate-target属性が指定され、validateコントローラにjapaneseターゲットが設定されます。また、「action: 'input->validate#japanese'」の指定でdata-action属性が指定され、フィールド変更時(input)にvalidate#japaneseアクションを呼び出すことを指定します。これらの設定により、コントローラ内でテキスト入力フィールドとボタンの参照が可能になります。

アクションを記述する

 最後はアクションです。ここまでは、ヘルパーメソッドにオプションを指定していくだけで必要な設定が行えましたが、アクションの中身はJavaScriptのコーディングが必要です。とはいえ、あらかじめ決められたルールの中でコーディングすればよいのです。

リスト app/javascript/controllers/validate_controller.js
…略…
export default class extends Controller {
  static targets = [ "button", "japanese", "english"]		(1)
  static values = { valid: true, japanese: '', english: '' }	(2)

  connect() {		(3)
    this.japaneseValue = this.japaneseTarget.value	(4)
    this.englishValue = this.englishTarget.value
    this.validValue = this.japaneseValue != '' && this.englishValue != ''	(5)
  }

  japanese() {		(6)
    this.japaneseValue = this.japaneseTarget.value
    this.validValue = this.japaneseValue != '' && this.englishValue != ''
  }

  english() {		(7)
    this.englishValue = this.englishTarget.value
    this.validValue = this.japaneseValue != '' && this.englishValue != ''
  }

  validValueChanged() {		(8)
    this.buttonTarget.disabled = !this.validValue
  }

 StimulusもRailsと同様に、設定より規約(CoC)となっています。そのため、非常に簡略化されたコーディングが可能です。(1)では、ターゲットのリストを配列で設定しておきます。HTML側のdata-validate-target属性で指定する値と一致している必要があります。(2)では、コントローラが保持する変数のリストをハッシュ(キー、初期値)で設定しておきます。

 (3)は既出の通りHTML要素とコントローラがひも付いたときに呼び出されるコールバック関数です。(4)で2つのテキスト入力フィールドから値を取り出し、それを(2)で宣言した変数に代入していますが、注目すべきはその書式です。ターゲット、変数ともに「this.xxxxTarget」「this.xxxxValue」の形式で参照できます。

 (5)は、2つのテキスト入力フィールドが空でないかを保持する変数への代入です。

 (6)と(7)は、data-action属性で指定されたアクションの本体です。それぞれ、テキスト入力フィールドから値を取り出し、(5)と同様に設定を行っています。

 最後の(8)は、Value APIという非常に便利な機能のための関数です。「xxxxValueChanged」という形式で関数を命名すると、対応する変数xxxxの値が変化すると呼び出されるコールバック関数になります。これにより、ボタンに対して有効/無効を設定する箇所を1つに絞れるというわけです。

まとめ

 今回は、前回に続きHotwrireについて、自由自在な書き換えができるTurbo Streamsと、より洗練されたJavaScriptの利用を支援するStimulusを紹介しました。次回は、JSONベースのWebサービスを開発するRuby on Rails APIを紹介します。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Railsによるクライアントサイド開発入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/16950 2022/12/27 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング