0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rails: JavaScript からコントローラの POST メソッドに対して非同期でリクエストを送信する

Last updated at Posted at 2024-01-02

一定の時間が経過したら強制的に投稿するフォームを作成する。
questionsコントローラのsubmitメソッドに対し、選択したchoice_idを送信する。

<%= form_with(url: submit_questions_path, method: :post) do |form| %>

    <%= form.radio_button :choice_id, 1 %>
    <%= form.radio_button :choice_id, 2 %>
    <%= form.radio_button :choice_id, 3 %>

<%= form.submit '投稿' %>

もちろん、上記のフォームで選択をして投稿ボタンを押せば投稿ができる。
しかし今回は、一定の時間が経ったらjavascriptで強制的に投稿させる。
それをしてくれるjavascriptは以下。
viewにベタ打ちなどして記述する。


var postAfterSeconds = 5;
setTimeout(function() {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '<%= submit_questions_path %>', true);
    var csrfToken = document.querySelector('meta[name="csrf-token"]').content;
    xhr.setRequestHeader('X-CSRF-Token', csrfToken);

    // 送信するデータ
    var data = new FormData();
    data.append('choice_id', '0');
    xhr.send(data);
}, postAfterSeconds * 1000); // 秒をミリ秒に変換

railsにはCSRF攻撃から守る機能があるため、csrfTokenを設定しないとリクエストはブロックされる。
var csrfToken = document.querySelector('meta[name="csrf-token"]').content;application.html.erb内header にある <% csrf-token %> を読み込み、 xhr.setRequestHeader('X-CSRF-Token', csrfToken)で設定している。


POSTメソッド questions#submitはざっくり以下の挙動をする。

questions_controller.rb

def submit
   choice = params[:choice_id]
   Choice.create(choice: choice)
   redirect_to questions_path
   #データ登録後にquestions/index viewを表示する
end

ここで問題が発生

javascriptでコントローラを呼び出してもquestions_path (questions/index)にredirectしない。
なのでデータ登録を行なった後に遷移する処理をjavascriptで書く。


var postAfterSeconds = 5;
setTimeout(function() {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '<%= submit_questions_path %>', true);
    var csrfToken = document.querySelector('meta[name="csrf-token"]').content;
    xhr.setRequestHeader('X-CSRF-Token', csrfToken);

    // 送信するデータ
    var data = new FormData();
    data.append('choice_id', '0');

    //POST後に実行する処理を追加
    xhr.onreadystatechange = function() {
     if (xhr.readyState == 4 && xhr.status == 200) {
      // ここにページ遷移の処理を追加
        window.location.href = '<%= questions_path %>';
      }

    xhr.send(data);

}, postAfterSeconds * 1000); // 秒をミリ秒に変換
  

JavaScriptでコントローラのメソッドを読んでもコントローラ内のredirectやViewへの接続、ページ遷移は勝手にやってくれなかった。
これに対し今回、サーバーサイドでやりたい処理をコントローラに、ページ遷移をjavascriptに書くことで、所望の挙動を実現できた。

もっと良い方法、またセキュリティ上の問題などがあれば、指摘いただけると幸いです。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?