RRUI-002 · Select · Turbo Frames

Select duplicates / reinitialises after Turbo Frame replace

When a form using rui_select lived in a Turbo Frame and validation failed (422), the frame replaced and the select could appear duplicated — native RRUI chrome stacked with a second enhanced select UI.

Fixed · 0.51.2 reported against 0.51.1 resolved 2026-08-07

Resolution (gem owner). Diagnosis confirmed: the gem gave legacy enhancers nothing to key off. As of v0.51.2, every native form control carries a data-rui marker so global initialisers (e.g. Materialize) can be scoped with select:not([data-rui]). That one-line host change was applied in StockLive’s initialiser. Only apps with a global enhancer need it; the marker ships to everyone.

Summary

Component RapidRailsUI::Select::Component (f.rui_select)
Status Fixed in 0.51.2 (marker) + host scope where enhancers exist
Cause No durable opt-out for legacy / global select enhancers on Turbo Frame replace
Now data-rui on native controls; hosts use select:not([data-rui])

Repro (historical)

  1. Put f.rui_select(…) inside a turbo_frame_tag form.
  2. Load a page that also initialises Materialize (or any global select enhancer) on turbo:frame-load / turbo:load.
  3. Submit so the server returns 422 and replaces the frame.
  4. Was: Select looks duplicated / reinitialised (wrapper + native control / stacked chevrons).
  5. Expected / now: One native RRUI select when enhancers respect :not([data-rui]).

What was going wrong

1. RRUI rendered a plain native select

<select … style="background-image: url('…chevron…')">
  <option>…</option>
</select>

CSS-only. No Stimulus. Documented as “no JavaScript required.”

2. Frame replace yielded a fresh select

The new markup had no “already enhanced” state. Host code that did document.querySelectorAll('select') + M.FormSelect.init wrapped it again.

3. No gem-level opt-out (pre-0.51.2)

What landed in the gem

Host initialiser pattern:
document.querySelectorAll('select:not([data-rui])')