一定の時間が経過したら強制的に投稿するフォームを作成する。
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はざっくり以下の挙動をする。
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に書くことで、所望の挙動を実現できた。
もっと良い方法、またセキュリティ上の問題などがあれば、指摘いただけると幸いです。