#前書き
某プログラミングスクールの最終課題として存在するフリーマーケットアプリの作成。その中でも特に実装が難しいと噂に聞くのがクレジットカードの登録、利用という過程を踏む商品の購入機能だと言われています。
かくいう僕もこの機能を実装するにあたってとても苦労しました。特にクレジットカードの登録はかなり躓きました・・・
qiitaには色々なpayjpに関する記事がありますし、それ以外にも色々な記事を当たりましたがうまくいかず、最終的にスクールの質問システムでなんとか解決しました。本当に親身になって解決してもらったんですが、途中から理解が追い付かず置いてきぼり状態になってしまったので、改めてここで振り返りながら、どのように実装したか説明していきます!
#まずは準備
payjpを介したクレジットカードの利用を行うためには準備が必要です。ここではその過程を簡単に振り返ります。
##準備1
payjpにユーザー登録します。ログインしてAPIをみるとテストの公開鍵と秘密鍵が確認できます。
##準備2
payjpのgemを読み込みましょう。
gem payjp
これでbundle installすればOKです。
##準備3
カードを登録するテーブルを作りましょう。
マイグレーションファイルは例として以下のようになります。
class CreateCards < ActiveRecord::Migration[5.2]
def change
create_table :cards do |t|
t.integer :user_id, null: false
t.string :customer_id, null: false
t.string :card_id, null: false
t.timestamps
end
end
end
payjpを通してカード番号などを保管するので、カード番号や使用期限などのカラムは作らないようにしましょう。マイグレーションし、アソシエーションはuserテーブルと組んでおきましょう。ここでは1対1で組んでおきます。
#ここからが本題!
これで最低限の準備は整いました。いよいよ本題です。コントローラー作り、そして登録フォーム作りに入っていきます。
##コントローラーの作成
まずはコントローラーを見ていきます。
class CardsController < ApplicationController
before_action :set_card
require "payjp"
def index
end
def new
@card = Card.new
end
def create
Payjp.api_key = ENV['PAYJP_SECRET_KEY']#ENVファイルなどに環境変数としてpayjpの鍵を登録しておく必要があります。
if params['payjp-token'].blank?
redirect_to action: :new
else
customer = Payjp::Customer.create(
email: current_user.email,
card: params['payjp-token'],
metadata: {user_id: current_user.id}
)
@card = Card.new(user: current_user, customer_id: customer.id, card_id: customer.default_card)
if @card.save
redirect_to card_path(current_user),notice: 'クレジットカード情報を登録しました。'
else
redirect_to action: :new
end
end
end
def show
if @card.present?
Payjp.api_key = ENV['PAYJP_SECRET_KEY']
customer = Payjp::Customer.retrieve(@card.customer_id)
@card_information = customer.cards.retrieve(@card.card_id)
end
end
def destroy
customer = Payjp::Customer.retrieve(@card.customer_id)
customer.delete
if @card.destroy
redirect_to action: index, notice: "削除しました"
else
redirect_to action: :index, alert: "削除できませんでした"
end
end
private
def set_card
@card = Card.where(user_id: current_user.id).first if Card.where(user_id: current_user.id).present?
end
end
カード情報を参照、削除できるようにshow、destroyアクションも作成しています。
payjp-tokenが多く登場しますが、payjpはカード情報のトークン化を行っており、入力した情報がpayjpに送られ、トークンが返されてそれを受け取ることで顧客情報とカードを紐付けたり、決済を行うとシステムのようです。これを入れることでトークンを取得し、カード情報の取得、削除が行えるようです。
このアクションに基づいてルーティングも行っておきましょう。
##いよいよ登録フォームの実装!
まずはフォームを作ります。
.creditinport
.creditinport__title
クレジットカード情報入力
.creditinport__credit-card
.creditinport__credit-card__inner
= form_with model: @card, method: :post, html: { name: "inputForm", id: "card_form"} do |f|
= f.label :カード番号, class: 'label'
%span.required 必須
%br
= f.text_field :number, type: 'text', class: 'input-number', placeholder: '半角数字のみ', maxlength: "16"
.card-deadline
= f.label :有効期限, class: 'deadline'
%span.required 必須
%br
.card-deadline__month
= f.select :exp_month, [["01",1],["02",2],["03",3],["04",4],["05",5],["06",6],["07",7],["08",8],["09",9],["10",10],["11",11],["12",12]],{} , class: 'input-deadline'
%span.month 月
.card-deadline__year
= f.select :exp_year, [["20",2020],["21",2021],["22",2022],["23",2023],["24",2024],["25",2025],["26",2026],["27",2027],["28",2028],["29",2029]],{} , class: 'input-deadline'
%span.year 年
.card-code
= f.label :セキュリティコード, class: 'label'
%span.required 必須
%br
= f.text_field :cvc, type: 'text', class: 'input-number', placeholder: 'カード背面4桁もしくは3桁の番号', maxlength: "4"
.add_card#card_token
= f.submit '追加する', class: 'add-btn', id: 'token_submit'
そしてもう一つ必要なこととして、payjpにデータを送信し、トークンを返すためにjavascriptを作動させる必要があります。僕が最も詰まってしまったところはこの部分です。完成図は以下の通りです。ちなみにjqueryを使用しています。
document.addEventListener(
'turbolinks:load', e => { //僕の場合tubrolinksがないとまともに動作しませんでした。
if ($("#card_form") != null) {
Payjp.setPublicKey("pk_test_ここにはそれぞれの公開鍵を入れます。");
const submitBtn = $("#token_submit") //フォームの追加する部分のIDをここに入れます。
submitBtn.on("click", (e) => { //submitbtnにクリックイベントを発火
e.preventDefault();
let card = {
number: document.getElementById("card_number").value,
cvc: document.getElementById("card_cvc").value,
exp_month: document.getElementById("card_exp_month").value,
exp_year: document.getElementById("card_exp_year").value //カード番号、セキュリティコード、有効期限を登録
};
Payjp.createToken(card, (status, response) => {
if (status === 200) { //statusが200の場合は通信成功。httpstatusを表し、400以上だと何らかの障害があることになります。
$("#card_number").removeAttr("name");
$("#card_cvc").removeAttr("name");
$("#card_exp_month").removeAttr("name");
$("#card_exp_year").removeAttr("name"); //送信したデータが自分のデータベースに登録されないよう削除
$("#card_token").append(
$('<input type="hidden" name="payjp-token">').val(response.id)
);//トークンを送信できるようにする。
alert("登録が完了しました");
$("#card_form")[0].submit();
} else {
alert("カード情報が正しくありません。");
}
});
});
}
}
);
僕の場合はクリックイベントが発火できずに苦戦しました。長い記事になりましたが、少しでも参考になれば幸いです。初学者などで間違いや意見などあれば教えていただけると幸いです!