プログラミング学習中で、これはメモしたいと思ったものを、自分ように分かりやすく残しておきます。
PAYJPを導入して、決済システムを実装したい!
テスト用のカード情報を入力して、決済が完了している状態です。
決済が成功しない...
まずは、payjp
のgemを導入し、学習した通りにJavaScriptのファイルを作ったり、コントローラーやビューへ記述しました。
元の画面に戻ってしまう...
(んん?? トークンが空っぽだと???)
これはコントローラーで、決済が成功しなかったら画面が変わらないように設定しており、エラーも表示させるようにしているからですが、最初は原因が分かりませんでした...
現在のコントローラーのコードはこちらです。(読みづらいかと思いますが、長くなるのでcreateアクションの部分のみ抜粋しております。)
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の記述はこちらです。
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で停止しているので、そこでコンソールを確認すると、
カード情報はしっかり受け取れているみたいです!
しかし、ステータスが400
なのでトークンが生成できない...
カード情報が受け取れているのに、なんで???
解決
そこで、知識のある方に相談させて頂き、ようやく解決しました!
取得するcard情報を格納する記述に誤りがあったみたいです。
この部分の記述の、
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")}`,
};
と記述することで、
まとめ
PAYJP
を導入する時は、取得したcard情報を格納する記述を、決まっている形式の記述にする必要がある。
binding_pry
とconsole.log()
を使うことで、どこで不具合が起きているのかを探すことができる。