LoginSignup
2
3

More than 1 year has passed since last update.

【Rails】javascriptのfetchを使って非同期通信(POST)を実装してみた

Last updated at Posted at 2021-05-03

初めに

railsにデータを保存する際(post)にfetchを使って非同期通信を実現できるのではないかと思い、学習した内容をもとに纏めてみました。

※内容に間違いなどがある場合はご指摘をよろしくお願いします。

前回の記事:https://qiita.com/redrabbit1104/items/1ce9f665a0fcd1d99bb2
https://qiita.com/redrabbit1104/items/b8b61a72f849fa3e8881
https://qiita.com/redrabbit1104/items/02bc16cf5abd4ed10ec1
https://qiita.com/redrabbit1104/items/c131c46897bfdf86e08b
https://qiita.com/redrabbit1104/items/806ef9849f4b0962ceaa

やりたいこと

railsの投稿formから入力した内容をfetchを使ってrequest(post)を送り、保存されたデータのresponseをブラウザに表示させること。

前提

Macでrailsアプリの新規作成及びdatabaseの作成などが終わっている。

作業手順

  • ①tableを準備(modelを作成)
  • ②routing
  • ③view
  • ④controller
  • ⑤javascriptを用意する
  • ⑥結果

tableを準備(modelを作成)

まずはデータを保存するためのtableを用意します。テーブル名はtestとしました。

 rails g model test
      invoke  active_record
      create    db/migrate/20210502224447_create_tests.rb
      create    app/models/test.rb
      invoke    rspec
      create      spec/models/test_spec.rb
      invoke      factory_bot
      create        spec/factories/tests.rb

生成された20210502224447_create_tests.rbファイルを開き、カラム名がnameでstring型のとてもシンプルなカラムを作ります。

class CreateTests < ActiveRecord::Migration[6.0]
  def change
    create_table :tests do |t|
      t.string :name
      t.timestamps
    end
  end
end

migrateファイルが出来上がりましたので、migrationしテーブルを生成します。

 rails db:migrate
== 20210502224447 CreateTests: migrating ======================================
-- create_table(:tests)
   -> 0.0399s
== 20210502224447 CreateTests: migrated (0.0400s) =============================

routing

railsを起動したらトップページに入力formを表示させたいので、その記述をします。また、testモデルは画面に表示するためのページ(view)と保存するためのcontroller側の記述が必要なため、resourcesをindexとcreateだけにします。

Rails.application.routes.draw do
  root "tests#index"
  resources :tests, only: [:index, :create]
end

view

画面に表示するためのページを作成します。この時にrails g controller testというコマンドでcontrollerファイルも一緒に生成します。

 rails g controller tests
      create  app/controllers/tests_controller.rb
      invoke  erb
      create    app/views/tests
      invoke  rspec
      create    spec/requests/tests_spec.rb
      invoke  helper
      create    app/helpers/tests_helper.rb
      invoke    rspec
      create      spec/helpers/tests_helper_spec.rb
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/tests.scss

生成されたapp/views/testsフォルダにindex.html.erbファイルを作り、以下のように記述します。

#responseとして戻ってきた内容を描画するところ
<div id="list">         
</div>

#testテーブルに保存されたnameカラムを全て表示
<% @tests.each do |test| %>       
   <%= test.name %>
   <br>
<% end%>

#testテーブルにnameを投稿するための入力フォーム
<%=form_with url: "/tests" , method: :post do |form| %>          
  <%= form.text_field :test %>
  <%= form.submit '投稿する' %>
<% end %>

fetchで非同期通信をして戻ってきたresponseを描画するところと、テーブルに保存されたデータを表示させる場所、そしてtestテーブルにnameデータを保存するための入力フォームを用意しました。

controller

indexアクションにはtestテーブルに保存されているnameを全て取得し、@testsに格納します。また、createアクションにはフォームから入力されたnameを保存し、json形式でresponseを返す処理を記述します。

class TestsController < ApplicationController

  def index
    @tests = Test.all.order(id: "DESC")         #テストテーブルのデータを全て取得し、@testsに格納
  end

  def create
    name = Test.create(name: params[:name])    #フォームから入力したnameをtestテーブルに保存。その結果を変数testに格納。
    render json:{ test: name }     #変数testに格納されているnameデータをjson形式でresponseとして返す。
  end

end

javascriptを用意する

app/javascriptの直下にtest.jsを作成します。また、app/javascript/packsのapplication.jsファイルを開き、先ほど作成したtest.jsを読み込むようにします。

require("@rails/ujs").start();
require("turbolinks").start();
require("@rails/activestorage").start();
require("channels");
require("../test");                  //追記

test.jsには以下のように記述します。test関数を用意してフォームの投稿するボタンをクリックするとfetchで非同期通信が行われます。responseはjson形式で戻ってきて、受け取ったデータをlist要素の後に追加します。

//test関数の定義
function test() {
  const submit = document.querySelector(".submit_test");
  if (!submit) {
    return false;
  }
  submit.addEventListener("click", (event) => {
    const formData = new FormData(document.querySelector(".test_form"));
    const url = "/tests";
    const post_options = {
      method: "post",
      body: formData,
    };
    fetch(url, post_options)
      .then((response) => {
        return response.json();
      })
      .then((item) => {
        const list = document.getElementById("list");
        const formText = document.querySelector(".input_name");
        const HTML = `
                    <div>${item.test.name}</div>
                    `;
        list.insertAdjacentHTML("afterend", HTML);
        formText.value = " ";
      });
    event.preventDefault();
  });
}

window.addEventListener("load", test);

ここで注意したいのは、responseのitemはpromiseであり、その中にtestというオブジェクトが格納されています。
スクリーンショット 2021-05-03 9.40.11.png
testというオブジェクトにはデータを保存する際のパラメーターがハッシュの形で入っています。nameカラムのデータに接続するにはitem.nameではなく、item.test.nameにする必要があります。

結果

railsを立ち上げ、投稿してみます。投稿した内容がページの更新をしなくても表示されるようになりました。
スクリーンショット 2021-05-03 9.46.00.png

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3