1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】PAYJPでトークン生成時のエラー解決

Last updated at Posted at 2020-09-20

プログラミング学習中で、これはメモしたいと思ったものを、自分ように分かりやすく残しておきます。

PAYJPを導入して、決済システムを実装したい!

今回もっていきたいゴールはこちらです。
スクリーンショット 2020-09-20 9.45.56.png

テスト用のカード情報を入力して、決済が完了している状態です。

決済が成功しない...

まずは、payjpのgemを導入し、学習した通りにJavaScriptのファイルを作ったり、コントローラーやビューへ記述しました。

そして、テスト用のカード情報を打ち込んで、
スクリーンショット 2020-09-20 10.01.28.png

購入ボタンを押しますが、
スクリーンショット 2020-09-20 10.14.43.png

元の画面に戻ってしまう...
(んん?? トークンが空っぽだと???)

これはコントローラーで、決済が成功しなかったら画面が変わらないように設定しており、エラーも表示させるようにしているからですが、最初は原因が分かりませんでした...

現在のコントローラーのコードはこちらです。(読みづらいかと思いますが、長くなるのでcreateアクションの部分のみ抜粋しております。)

****_controller.rb
  def create
    @order = ItemOrder.new(order_params)
    if @order.valid?
      pay_item
      @order.save
      return redirect_to root_path
    else
      render 'new'
    end
  end

カードの情報を受け取って、トークンを生成するためのJavaScriptの記述はこちらです。

****.js

const pay = () => {
  Payjp.setPublicKey(process.env.PAYJP_PUBLIC_KEY);
  const form = document.getElementById("charge-form");
  form.addEventListener("submit", (e) => {
    e.preventDefault();
 
    const formResult = document.getElementById("charge-form");
    const formData = new FormData(formResult);

    const card = {
      card_number: formData.get("card-number"),
      card_cvc: formData.get("card-cvc"),
      card_exp_month: formData.get("card-exp-month"),
      card_exp_year: `20${formData.get("card-exp-year")}`,
    };
    Payjp.createToken(card, (status, response) => {
      if (status == 200) {
        const token = response.id;
        const renderDom = document.getElementById("charge-form");
        const tokenObj = `<input value=${token} type="hidden" name='token'>`;
        renderDom.insertAdjacentHTML("beforeend", tokenObj);
      }
      document.getElementById("card-number").removeAttribute("name");
      document.getElementById("card-cvc").removeAttribute("name");
      document.getElementById("card-exp-month").removeAttribute("name");
      document.getElementById("card-exp-year").removeAttribute("name");
 
      document.getElementById("charge-form").submit();
      document.getElementById("charge-form").reset();
    });
  });
 };
 window.addEventListener("load", pay);

現状把握

どこが間違っているのかを見るために、pry-railsのgemを導入し、createアクションにbinding.pryを記述して、paramsの中身を確認しました。

pry(#<OrdersController>)> params
=> <ActionController::Parameters {"authenticity_token"=>"pvPlrZPKlxtcYotX8kK4N/OjbTuWNkiq5bOCJxqNI+OYt59wXZuTClFnz7XDmAVWelWQJraGSTdIccYspnstlw==", "item_order"=>{"postal_code"=>"555-0000", "prefecture_id"=>"3", "city"=>"市区町村", "block_number"=>"番地", "building_name"=>"建物名", "phone_number"=>"09012345678"}, "controller"=>"orders", "action"=>"create", "id"=>"1"} permitted: false>

たしかに、tokenがいない....
authenticity_tokenは全く別のものだそうです。)

ということは、うまくtokenが生成されていない可能性があります。

次に、JavaScriptへの記述を調べるために,console.log()を使用して調べました。

const pay = () => {
  Payjp.setPublicKey(process.env.PAYJP_PUBLIC_KEY);
  console.log(process.env.PAYJP_PUBLIC_KEY)
  // 環境変数が定義できているか確認
  const form = document.getElementById("charge-form");
  form.addEventListener("submit", (e) => {
    e.preventDefault();
 
    const formResult = document.getElementById("charge-form");
    const formData = new FormData(formResult);

    const card = {
      card_number: formData.get("card-number"),
      card_cvc: formData.get("card-cvc"),
      card_exp_month: formData.get("card-exp-month"),
      card_exp_year: `20${formData.get("card-exp-year")}`,
    };
    console.log(card)
    // カード情報が受け取れているかの確認
    Payjp.createToken(card, (status, response) => {
      console.log(status)
      // ステータスの数字を確認
      if (status == 200) {
        const token = response.id;
        const renderDom = document.getElementById("charge-form");
        const tokenObj = `<input value=${token} type="hidden" name='token'>`;
        renderDom.insertAdjacentHTML("beforeend", tokenObj);
      }
      document.getElementById("card-number").removeAttribute("name");
      document.getElementById("card-cvc").removeAttribute("name");
      document.getElementById("card-exp-month").removeAttribute("name");
      document.getElementById("card-exp-year").removeAttribute("name");
 
      document.getElementById("charge-form").submit();
      document.getElementById("charge-form").reset();
    });
  });
 };
 window.addEventListener("load", pay);

そして、binding_pryで停止しているので、そこでコンソールを確認すると、
スクリーンショット 2020-09-20 10.41.00.png
カード情報はしっかり受け取れているみたいです!
しかし、ステータスが400なのでトークンが生成できない...

カード情報が受け取れているのに、なんで???

解決

そこで、知識のある方に相談させて頂き、ようやく解決しました!
取得するcard情報を格納する記述に誤りがあったみたいです。

この部分の記述の、

****.js
const card = {
      card_number: formData.get("card-number"),
      card_cvc: formData.get("card-cvc"),
      card_exp_month: formData.get("card-exp-month"),
      card_exp_year: `20${formData.get("card-exp-year")}`,
    };

card_number:card_cvc:card_exp_month:card_exp_year:の記述をすると、正しくPayjpと通信しないみたいです。

この形は決まっていると教わりまして、
number:cvc:exp_month:exp_year:というように記述を直しました。

const card = {
      number: formData.get("card-number"),
      cvc: formData.get("card-cvc"),
      exp_month: formData.get("card-exp-month"),
      exp_year: `20${formData.get("card-exp-year")}`,
    };

と記述することで、

無事ステータスも、
スクリーンショット 2020-09-20 10.59.02.png
200になり、

決済も成功させることができました!
スクリーンショット 2020-09-20 11.02.39.png

まとめ

PAYJPを導入する時は、取得したcard情報を格納する記述を、決まっている形式の記述にする必要がある。
binding_pryconsole.log()を使うことで、どこで不具合が起きているのかを探すことができる。

1
4
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
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?