Rails7 stimulusを使用してAjaxフォームを実装する

  • 作成日 2024.06.27
  • rails
Rails7 stimulusを使用してAjaxフォームを実装する

Ruby on Rails 7で、stimulusを使用してAjaxフォームを実装するサンプルコードです。

環境

  • OS Ubuntu24.04
  • rails 7.1.3

Stimulusのインストール

Rails 7では、Stimulusがデフォルトでセットアップされているため、追加のインストールは不要ですが、念のため以下のコマンドで確認します。

$ bundle exec rails stimulus:install

Scaffoldの作成

サンプルデータとして、Itemモデルを作成します。

$ rails generate scaffold Post title:string content:text
$ rails db:migrate

Stimulusコントローラーの作成と設定

Stimulusコントローラーを生成します。

$ rails generate stimulus form

生成されたコントローラーを以下のように編集します。

// app/javascript/controllers/form_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["output"]

  connect() {
    this.element.addEventListener("ajax:success", this.success.bind(this));
    this.element.addEventListener("ajax:error", this.error.bind(this));
  }

  success(event) {
    const [data, status, xhr] = event.detail;
    this.outputTarget.innerHTML = `<p>Post created: ${data.title}</p>`;
    this.element.reset();
  }

  error(event) {
    const [data, status, xhr] = event.detail;
    this.outputTarget.innerHTML = `<p>Error: ${data.errors.join(", ")}</p>`;
  }
}

HTMLの設定

app/views/posts/index.html.erbを以下のように編集します。

<h1>New Post</h1>

<div data-controller="form">
  <%= form_with(model: Post.new, remote: true, data: { action: "ajax:success->form#success ajax:error->form#error" }) do |form| %>
    <div>
      <%= form.label :title %>
      <%= form.text_field :title %>
    </div>
    <div>
      <%= form.label :content %>
      <%= form.text_area :content %>
    </div>
    <div>
      <%= form.submit "Create Post" %>
    </div>
  <% end %>

  <div data-form-target="output"></div>
</div>

<h2>All Posts</h2>

<% @posts.each do |post| %>
  <div>
    <strong><%= post.title %></strong>
    <p><%= post.content %></p>
  </div>
<% end %>

コントローラーの編集

フォームの送信結果を処理するために、PostsControllerを編集します。

app/controllers/posts_controller.rbを以下のように編集します。

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.all
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)
    respond_to do |format|
      if @post.save
        format.json { render json: @post, status: :created }
      else
        format.json { render json: { errors: @post.errors.full_messages }, status: :unprocessable_entity }
      end
    end
  end

  private

  def post_params
    params.require(:post).permit(:title, :content)
  end
end

Railsサーバーの起動

最後に、Railsサーバーを起動して動作を確認します。
※自分の環境は外部からアクセスできるようにして起動してます。

$ rails s -b 0.0.0.0

ブラウザからhttp://localhost:3000/postsにアクセスすると、Ajaxが正常に動作することが確認できます。