railsとAjaxが上手く連動してくれない時の確認
現在railsでアプリケーションを作成していて非同期通信を導入しようとしていました。
ですが、何が原因なのか上手く動作する時としない時があり原因不明だったのですが、なんとか解決に導いてもらえたので整理しておくために記録します。
function post (){
const submit = document.getElementById("submit");
submit.addEventListener("click", () => {
const form = document.getElementById("form");
const formData = new FormData(form);
const XHR = new XMLHttpRequest();
XHR.open("POST", "/posts", true);
XHR.responseType = "json";
XHR.send(formData);
});
};
window.addEventListener('load', post);
class PostsController < ApplicationController
def index
@posts = Post.order(id: "DESC")
end
def create
Post.create(content: params[:content])
redirect_to action: :index # 追記する
end
end
<h1>Ajaxの練習</h1>
<%= form_with url: "/posts", method: :post,id: "form" do |form| %>
<%= form.text_field :content %>
<%= form.submit '投稿する' , id: "submit" %>
<% end %>
<div id="list">
</div>
<% @posts.each do |post| %>
<div class="post">
<div class="post-date">
投稿日時:<%= post.created_at %>
</div>
<div class="post-content">
<%= post.content %>
</div>
</div>
<% end %>
状態
記述の途中なので中途半端な状態でかつjsファイルでもDBに保存しようとしているし、controllerでもcreateアクションでも保存をしようとしています。
記述の途中上"sbumit"の所をクリックをすればAjaxのリクエストとデフォルトのリクエストが2つ届き同じ@postがeach文で展開されるはずです。
が・・・
たまに2つリクエストが届く時もあるし、1つしか届かないときもあるのです・・・・
ターミナル
Parameters: {"authenticity_token"=>"VX63mzlfvUpBtp7dMhUJONWk3qiIjgpnCcBO+7KjwJrE/FaE30AddvJjJSaDVhMWUO2kuO3gM38jVmKTJ5Kd+g==", "content"=>"あああ", "commit"=>"投稿する"}
(0.2ms) BEGIN
↳ app/controllers/posts_controller.rb:13:in `create'
Post Create (3.9ms) INSERT INTO `posts` (`content`, `created_at`, `updated_at`) VALUES ('あああ', '2021-10-18 11:27:48.286331', '2021-10-18 11:27:48.286331')
↳ app/controllers/posts_controller.rb:13:in `create'
(0.5ms) COMMIT
↳ app/controllers/posts_controller.rb:13:in `create'
Redirected to http://localhost:3000/
Completed 200 OK in 10ms (ActiveRecord: 4.6ms | Allocations: 2944)
Started GET "/" for ::1 at 2021-10-18 20:27:48 +0900
Processing by PostsController#index as HTML
Rendering posts/index.html.erb within layouts/application
Post Load (0.9ms) SELECT `posts`.* FROM `posts` ORDER BY `posts`.`id` DESC
↳ app/views/posts/index.html.erb:9
Rendered posts/index.html.erb within layouts/application (Duration: 6.4ms | Allocations: 2807)
[Webpacker] Everything's up-to-date. Nothing to do
Completed 200 OK in 30ms (Views: 22.3ms | ActiveRecord: 0.9ms | Allocations: 6757)
Started GET "/" for ::1 at 2021-10-18 20:27:51 +0900
Processing by PostsController#index as HTML
Rendering posts/index.html.erb within layouts/application
Post Load (0.7ms) SELECT `posts`.* FROM `posts` ORDER BY `posts`.`id` DESC
↳ app/views/posts/index.html.erb:9
Rendered posts/index.html.erb within layouts/application (Duration: 3.6ms | Allocations: 2806)
[Webpacker] Everything's up-to-date. Nothing to do
Completed 200 OK in 14ms (Views: 12.3ms | ActiveRecord: 0.7ms | Allocations: 6749)
Started POST "/posts" for ::1 at 2021-10-18 20:28:05 +0900
Started POST "/posts" for ::1 at 2021-10-18 20:28:05 +0900
Processing by PostsController#create as JS
Processing by PostsController#create as */*
Parameters: {"authenticity_token"=>"t4UG50/3a8K3eXgqHtzlj4S98OroyzTZjCB+NhYuuLU4kCi1fb43Zzz42ZHVSTAuC7OJe6qdQqXna9dDX06ggA==", "content"=>"メモ④", "commit"=>"投稿する"}
Parameters: {"authenticity_token"=>"t4UG50/3a8K3eXgqHtzlj4S98OroyzTZjCB+NhYuuLU4kCi1fb43Zzz42ZHVSTAuC7OJe6qdQqXna9dDX06ggA==", "content"=>"メモ④"}
(1.4ms) BEGIN
↳ app/controllers/posts_controller.rb:13:in `create'
(2.5ms) BEGIN
↳ app/controllers/posts_controller.rb:13:in `create'
Post Create (11.0ms) INSERT INTO `posts` (`content`, `created_at`, `updated_at`) VALUES ('メモ④', '2021-10-18 11:28:05.807091', '2021-10-18 11:28:05.807091')
Post Create (2.5ms) INSERT INTO `posts` (`content`, `created_at`, `updated_at`) VALUES ('メモ④', '2021-10-18 11:28:05.809068', '2021-10-18 11:28:05.809068')
↳ app/controllers/posts_controller.rb:13:in `create'
↳ app/controllers/posts_controller.rb:13:in `create'
(0.6ms) COMMIT
(0.6ms) COMMIT
↳ app/controllers/posts_controller.rb:13:in `create'
↳ app/controllers/posts_controller.rb:13:in `create'
Redirected to http://localhost:3000/
Redirected to http://localhost:3000/
同じ動作をしているのですが、よくターミナルをみてみると"Post Load"の時と"Post Create"と動作していたりしています。
ちなみにjsファイルに"console.log("イベント")"を記述して動かしていたのでコンソール上でAjaxが読み込まれていたのは確認済みです。
現状としてはjsファイルからDBに保存される時もあれば、createアクションで保存される時がランダムで起きている状態でした。
原因
アクテビティモニタを見るとRubyが"%CPU"の8割締めていました。
あまりにもRubyが重すぎて連続投稿したらAjaxの読み込みにかなり時間がかかってしまい、それより先にcreateアクションのほうが先に動いていたためのばらつきでした。
・DBに1件だけ保存される時はcontrollerが動作
・2件DBに保存される時はjsファイルが動作
対処法
①ターミナルで
% ps aux | grep spring
を実行し状況を確認すると多くても2つぐらいしか可動していないはずのRubyファイルが3つ可動していました。
ちなみな通常ではアクテビティモニタ上で終了できるらしいのですが何度消しても復活していました。
②Rubyファイルの強制終了
% kill -9 ファイルの数字
サーバーを立ち上げたままタブを閉じてしまった時とかによくするkillコマンドをして終わらせます。
③確認
再び
% ps aux | grep spring
をしてちゃんと終了できていたか確認
結論
記述ミスではなくただAjaxの読み込みが異常に時間がかかっていただけ
でした・・・
今回はカリキュラム上偶然createアクションがあったためDBに保存されていたのですがなかったらただ動かないしエラーも出ないと思うと・・・
自信がない時は記述をうたがったり確認にめっちゃ時間をつかってしまうわりに結論に辿りつかけない魔のループにはいいてしまう人もいるとおもうので、この記事が誰かの助けになれば幸いです。