Help us understand the problem. What is going on with this article?

[Rails]ajaxでpostアクションを叩いたらsessionが拾えなかった。

どうもこんばんは、Rails学習2〜3ヶ月くらいのChihaです。
タイトル通り、jQueryからajaxでアクションを叩いて動かすと、それまで定義してきたsessionの値が拾えなくなる現象に遭遇&解決したので、ざっくりと書きます。

開発環境

  • Ruby on Rails 5.2.2
  • Ruby 2.5.1
  • jQuery

概要

ajaxからのpostリクエストを叩くと、アプリ側に持たせていたsessionの値が取得できなくなった。

signup.js
//何かしらの処理後
$.ajax({ 
          url: "/signup",
          type: "POST",//コントローラのアクションをpostで叩く
          data: {
            //送るデータとか
          },
          async: false //今回は同期通信でした
        })
signup_controller.rb(例)
#前のページでの入力項目をsession保存
def before_page_content
  session[:birthyear] = profile_params[:birthyear]
  session[:birthmonth] = profile_params[:birthmonth]
  session[:birthday] = profile_params[:birthday]
end

#ajaxで叩くcreateアクション
#/signup(method: :post)
def create
  ※下のcreateが失敗する
  @profile = Profile.create(
  birthyear: session[:birthyear],
  birthmonth: session[:birthmonth],
  birthday: session[:birthday]
  )
end

こんな感じのコードでjsから直接postメソッドのアクションを叩くと、それまでに取得して来ることができたはずのsessionの値が全部nilになっていた。そりゃ当然失敗する。

ターミナル
ActionController::InvalidAuthenticityToken

エラーはこういうのが出ました。

解決策

signup.js
//何かしらの処理後
$.ajax({ 
          url: "/signup",
          type: "POST",
          data: {
            //送るデータとか
          },
          //下の記述を追記
          beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
          },//ここまで
          async: false
        })

これで無事にcreateアクションでsessionの値を拾って処理ができるようになりました。

Rails not reloading session on ajax post
【Rails API】ActionController::InvalidAuthenticityTokenの解決方法
外部からPOSTできない?RailsのCSRF対策をまとめてみた

解決はこの辺りを参考にしました。
どうやら、RailsでのCSRF対策にjsからget以外のメソッドを叩いたのが悪かったようです。
【Rails API】ActionController::InvalidAuthenticityTokenの解決方法
詳しい理由とCSRFについてはこの記事に書かれてます。

トラブルの経緯

スクールでの開発にて、wizard形式(複数ページに渡りユーザー情報を入力させ、最後のページで一括createする形式)でのユーザー登録機能を実装していた時の話。
各ページで入力された値は、sessionとしてアプリ側に預ける形に(詳しくはそのうち)。
最終ページでクレジットの情報を登録する必要があったため、payjpを利用することに。

payjpでは、ユーザーが入力したクレジット情報をjavascript経由でpayjpに送り、トークンの情報を返す処理を行うことで、クレジット情報をRails側で使用せず、トークンを用いたユーザーのクレジットカード登録機能の実装、使用が可能となります。
こちらについては詳しくはpayjp.jsのリファレンス(カード情報のトークン化)で。

というわけで、最終ページでcreateではなく、payjp.jsでのトークン取得を経てcreateする形で実装することに。

つまり、jsでの処理を経由してpayjpからのトークンを取得したのち、トークンをjsから投げつつ、postメソッドのcreateアクションを叩く、という感じでの実装を考えた。

ここでjsからcreateアクションを叩くとsessionが一つも取得できなくなっていた。
要するに上記の症状が発生していた。

js側に記述を書き足すと解決した。

という流れになります。

かなりアバウトな感じになりましたが、詳しくは上記の参考記事にて。
クレジットカード登録を含めたwizard形式でのユーザー登録フォームの実装については、長くなりそうなので後日ということで。。。

最後に

引き続き気まぐれにトラブルや知った技術などを忘備録として書いていこうと思います。
まだまだ右も左もあやふやなド初心者ですので、より良いコード、間違った点などがあればご教授頂けると幸いです。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away