RailsのTrubo Frameを使ってpulldown変更時に非同期でデータ更新する

pulldown変更時に非同期更新したいというのは割とよくある話だと思いますが、 以前似たような実装をしたことがあるのですが、その時にはRailsで生成したformのsubmit方法がいまいちわからず Stimulus(js)でsubmitするということをやってました。

submitは、rails-ujsRails.fire を使ってるので、今後推奨されないですね。
そもそも、onChange時にsubmitしたいだけなのにjsのファイル追加してるのは微妙だなぁと思いながら書いていた記憶があります。

実装方法

例として書籍を表示する画面で、有効か無効かを選択できるプルダウン実装について記載します。

view

更新対象のhtmlをpartial化します。
(turbo_streamを直接viewに書く方法をとれば、必須ではないです。個人的にはわかりやすいのでpartila化しています。)

    td
      = render partial: "active", locals: { book: @book }

partial。

/# locals: (book:)
= turbo_frame_tag "active" do
  = form_with model: book do |f|
    = f.select :active, [['true', true], ['false', false]], { selected: book.active }, onChange: "this.form.requestSubmit();"

更新部分を turbo_frame_tag でくくります。 onChangeで requestSubmit() を呼んでいるのもポイントです。

あと、昨日紹介したStrict Localsも便利で良いです。 (RailsのStrict Localsをslimで使う

requestSbumit()

こちらで、submit() はトリガーしないけど、requestSubmit () はするみたいな話が載ってます。
ruby on rails 5 - How can I submit a form on input change with Turbo Streams? - Stack Overflow

確かに、以前は form.submit() が動かずに仕方なくRails.fire していました。

controller

あとは、turbo_streamで置き換えれば良いです。 以下のようにcontrollerでやっても良いですし、edit.turbo_stream.slim というようなturbo stream用のviewを用意して、実施しても良いです。

  def update
    @book = Book.find(params[:id])
    if @book.update(book_params)
      render turbo_stream: turbo_stream.replace("active", partial: "active", locals: { book: @book })
    else
      render json: @book.errors, status: :unprocessable_entity
    end
  end