基本

Ruby on Railsでフォーム入力を受け取りJSONで返す

Ruby on Railsでは、HTMLフォームから送信されたデータをコントローラーで受け取り、JSON形式でレスポンスを返すことができます。この仕組みは、Ajax通信を使った非同期処理やAPIエンドポイントの構築で頻繁に使われます。この記事では、フォームの作成からデータの受け取り、JSON応答の返却までの流れを解説します。

基本的な使い方

まず、フォームを含むビューとデータを受け取るコントローラーアクション、ルーティングを設定します。

config/routes.rb
Rails.application.routes.draw do
  get "test" => "test#index"
  post "test/submit" => "test#submit"
end
app/controllers/test_controller.rb
class TestController < ApplicationController
  def index
  end

  def submit
    name = params[:name]
    render json: { success: true, message: name }
  end
end

render json:を使うと、RubyのハッシュをJSON形式に変換してレスポンスとして返します。ブラウザやJavaScriptからは{"success":true,"message":"入力値"}のようなJSONデータを受け取ることができます。

フォームの作成

ビューにHTMLフォームを作成します。Ajax送信を行う場合は、通常のフォーム送信を防止してJavaScriptで処理します。

app/views/test/index.html.erb
<form id="myForm">
  <label for="name">名前</label>
  <input type="text" name="name" id="name">
  <button id="submitBtn" type="button">送信</button>
</form>

<div id="result"></div>

JavaScriptでAjax送信

Fetch APIを使って、フォームのデータを非同期でサーバーに送信し、JSON応答を受け取ります。

JavaScript
document.getElementById("submitBtn").addEventListener("click", function() {
  const name = document.getElementById("name").value;
  const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

  fetch("/test/submit", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-CSRF-Token": csrfToken
    },
    body: JSON.stringify({ name: name })
  })
  .then(response => response.json())
  .then(data => {
    document.getElementById("result").textContent = data.message;
  })
  .catch(error => {
    console.error("Error:", error);
  });
});

RailsではCSRFトークンの検証がデフォルトで有効になっています。Ajax通信を行う場合は、metaタグからトークンを取得して、リクエストヘッダーのX-CSRF-Tokenに含める必要があります。

Strong Parametersの使用

実際のアプリケーションでは、Strong Parametersを使って受け取るパラメータを制限するのが推奨されます。

app/controllers/test_controller.rb
class TestController < ApplicationController
  def submit
    permitted = params.permit(:name, :email, :age)

    if permitted[:name].present?
      render json: {
        success: true,
        data: {
          name: permitted[:name],
          email: permitted[:email],
          age: permitted[:age]
        }
      }
    else
      render json: {
        success: false,
        error: "名前は必須です"
      }, status: :unprocessable_entity
    end
  end
end

params.permitで許可するパラメータを明示的に指定することで、不正なパラメータの送信を防ぎます。バリデーションエラーの場合はstatus: :unprocessable_entity(422)を返すのが一般的です。

モデルと連携したJSON応答

データベースへの保存と組み合わせた実践的な例も見てみましょう。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def create
    @post = Post.new(post_params)

    if @post.save
      render json: {
        success: true,
        post: {
          id: @post.id,
          title: @post.title,
          created_at: @post.created_at.strftime("%Y/%m/%d %H:%M")
        }
      }, status: :created
    else
      render json: {
        success: false,
        errors: @post.errors.full_messages
      }, status: :unprocessable_entity
    end
  end

  private

  def post_params
    params.require(:post).permit(:title, :content)
  end
end
ポイント

APIとして使う場合は、ApplicationControllerの代わりにActionController::APIを継承するとよいでしょう。CSRFトークンの検証が不要になるなど、API専用の軽量なコントローラーが使えます。

注意

CSRFトークンの検証を無効にするskip_before_action :verify_authenticity_tokenは、セキュリティ上のリスクがあるため、やむを得ない場合にのみ使用してください。

まとめ

  • render json:でRubyのハッシュをJSON形式で返せる
  • Ajax通信にはFetch APIを使い、X-CSRF-Tokenヘッダーを含める
  • Strong Parametersで受け取るパラメータを制限してセキュリティを確保する
  • 成功時は:created(201)、エラー時は:unprocessable_entity(422)のステータスを返す
  • モデルのバリデーションエラーはerrors.full_messagesで取得してJSON応答に含める
  • API専用コントローラーにはActionController::APIを使用する