2024-12-03
simple_formとStimulusを併用していて地味に詰まったポイント
simple_form
Hotwire
Stimulus
Ruby on Rails
TL;DR
- simple_formでケバブケースに変換されたdata-target属性と、Stimulusでtargetを参照する際に使用される識別子のミスマッチでtargetが参照できなくなっていた
- simple_formは属性名をHTMLに合わせてスネークケースからケバブケースに変換してくれる
- Stimulusで識別子として登録されるのはControllerのファイル名=スネークケース
- StimulusのController名が2単語以上で構成される場合、input_htmlでdata属性のハッシュではなく、文字列で
"data-controller_name-target"
のように属性を設定する必要がある
- input_html: {
- data: {
- "controller_name-target": "target",
- action: "change->controller_name#action"
- }
- }
+ input_html: {
+ "data-controller_name-target": "target",
+ data: { action: "change->controller_name#action" }
+ }
地味に詰まったポイント
Stimulusでは、参照したい要素に名前を付けてControllerで参照することができます。
user_role_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['select'];
connect() {
// data-user_role-target属性値が"select"の要素が取得できる
this.selectTarget.doSomething();
// ...
}
}
Viewの方で参照したい要素にdata-controller_name-target属性を設定しますが、最初はケバブケースで指定していタコとにより、上記connect関数内でtargetが参照できなくて困っていました。
_form.html.erb
<%= simple_form_for @user do |f| %>
<%= f.input :name %>
<%= f.association :roles, collection: Role.all,
input_html: {
class: "select2 browser-default",
data: {
"user-role-target": "select",
action: "change->user_role#hoge"
}
}
%>
<%= f.button :submit %>
<% end %>
そこでControllerのファイル名と合わせてスネークケースに修正すれば動くのでは?と以下のように修正。
_form.html.erb
<%= simple_form_for @user do |f| %>
<%= f.input :name %>
<%= f.association :roles, collection: Role.all,
input_html: {
class: "select2 browser-default",
data: {
"user_role-target": "select",
action: "change->user_role#hoge"
}
}
%>
<%= f.button :submit %>
<% end %>
原因のあたりの付け方は悪くありませんでしたが、これでも動かず。
Chrome DevToolsを確認したところ、simple_formの仕様?で属性をケバブケースに変換してくれていることがわかりました。
最終的に辿り着いたのが、以下のような形です。
最悪の場合、部分的にsimple_formを使わずに自前で書くことも考えましたが、回避方法があってよかったです。
_form.html.erb
<%= simple_form_for @user do |f| %>
<%= f.input :name %>
<%= f.association :roles, collection: Role.all,
input_html: {
class: "select2 browser-default",
"data-user_role-target": "select",
data: {
action: "change->user_role#hoge"
}
}
%>
<%= f.button :submit %>
<% end %>
補足
ちなみにtarget名はControllerのプロパティとして直接マッピングされるためキャメルケースにする必要があります。
命名規則が入り混じっていて非常に混乱する...。
おわりに
明日は @yubachiri さんによる プログラミング言語を作る 本を読んだところまでまとめてみる です。