はじめに
例によって、某プログラミングスクールの最終課題である、フリマアプリのクローンサイト作成において、購入機能実装時にPay.jpを利用したので、健忘録としてここに記す。
今回は主にクレジットカード登録機能の実装に取り掛かります。
(お待たせいたしました、、、)
バージョン情報
ruby '2.5.1'
Rails '5.2.4.2'
実装の流れ
- 実装の準備・APIの導入
- モデルの作成・クレジットカード登録 ← 今回の実装内容
- クレジットカード詳細表示・削除
- クレジットカード購入(決済)機能
前提条件として
- 記載はhaml記法で
- 私の参考にしたrailsにhamlを導入するやり方はこちら、、
- ユーザー登録機能として、gemの
devise
を利用しています。 なのでcurrent_user
などのdevise
のメソッドが随所に出てきます - 参考記事: 【Rails】deviseを導入してみる
今回の実装機能のダイジェスト
クレジットカード登録の様子
- まず、新規登録画面で特定のカード情報が入力される
- 入力された情報は、トークン化処理(第3者にカード情報が漏れないように暗号化)する。(jQueryの
payjp.js
で実装) - トークン化された情報は、自アプリの任意の自テーブルで登録される
- 登録が完了したら(今回の例では)createビューが表示される
- もし、登録途中でエラーがあれば、その旨のflashメッセージが表示される。
注意!
クレジットカード登録のテストの際には以下のサイトのテスト用のクレジット番号を必ずお使いください!
テストカード
有効期限は現在以降の年と月であればなんでもOK
CVC(セキュリティコード)はなんでもOK!
間違ってもご自身のカード番号は使わないように
前置きはこれくらいで、いよいよ実装!
いよいよ実装! まずはモデルの作成
(こちらは主旨に若干外れてしまいますので、さらっと行きます。参考程度でお願いします)
今回は以下のテーブルを作成しました。
credit_cardsテーブル
Column | Type | Options |
---|---|---|
user_id | references | null: false,foreign_key: true |
customer_id | string | null: false |
card_id | string | null: false |
credit_cardsマイグレーションファイル
class CreateCreditCards < ActiveRecord::Migration[5.2]
def change
create_table :credit_cards do |t|
t.references :user, null: false, foreign_key: true
t.string :customer_id, null: false
t.string :card_id, null: false
t.timestamps
end
end
end
こちらをrails db:migrate
$ rails db:migrate
(もしDBのテーブル作成に不安があれば、(私が参考にした)こちらのサイトをご覧ください)
ちなみにカード情報そのものを保存することは禁止されています。
カード情報非通過化対応のお願い
アソシエーションはこんな感じ
class CreditCard < ApplicationRecord
belongs_to :user
end
(今回は1人1枚のみクレジットカード登録できるように設定(has_one
で))
# 今回の実装に不要なアソシエーションは省略
class User < ApplicationRecord
has_one :credit_card, dependent: :destroy
end
コントローラーを作る!
今回は(credit_cardsモデルもあることだし)credit_cardsコントローラーを作って、そちらにアクションを記載していきます。
$ rails g controller Credit_cards
今回はクレジットカード新規登録ということで、先に以下のようにコントローラーにnewアクション
とcreateアクション
を追記
(newアクション後のトークン作成処理をまだ行なっていないため、createアクション
の内容が分かりにくいかもしれませんが、分からなければ一旦置いておいてOK!)
class CreditCardsController < ApplicationController
require "payjp" #PAYJPとやり取りするために、payjpをロード
def new
# 後ほど、showアクション(登録クレジットカード詳細表示機能)実装時に追記します。
end
def create
# 前回credentials.yml.encに記載したAPI秘密鍵を呼び出します。
Payjp.api_key = Rails.application.credentials.dig(:payjp, :PAYJP_SECRET_KEY)
# 後ほどトークン作成処理を行いますが、そちらの完了の有無でフラッシュメッセージを表示させます。
if params["payjp_token"].blank?
redirect_to action: "new", alert: "クレジットカードを登録できませんでした。"
else
# 無事トークン作成された場合のアクション(こっちが本命のアクション)
# まずは生成したトークンから、顧客情報と紐付け、PAY.JP管理サイトに登録
customer = Payjp::Customer.create(
email: current_user.email,
card: params["payjp_token"],
metadata: {user_id: current_user.id} #最悪なくてもOK!
)
# 今度はトークン化した情報を自アプリのCredit_cardsテーブルに登録!
@card = CreditCard.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
# 無事、トークン作成とともにcredit_cardsテーブルに登録された場合、createビューが表示されるように条件分岐
if @card.save
#もしcreateビューを作成しない場合はredirect_toなどで表示ビューを指定
else
redirect_to action: "create"
end
end
end
end
しれっと記載してますが、フラッシュメッセージ表示機能も実装しています。
(なので、フラッシュメッセージ機能実装しないとうまく動かないかも)
参考にした記事: 【Rails】flashメッセージを使用して簡易メッセージを表示させる詳しい方法と解説
ついでにルーティングも設定しておく
Rails.application.routes.draw do
# したの方に追記
resources :credit_cards, only: [:new, :create] do
end
end
コントローラーの記載、ルーティングは完了!
ビューを記載(基本的にレイアウトなどはお好みで、、)
ビューの表示例
newアクション
のviewを記載
ちなみに部分テンプレートを使用してます(ファイル名を参照!)。
基本的にはこの次の、jQueryのpayjp.js
記述時のid名との照らし合わせ用として、ご確認ください。
.card_add
.title クレジットカード情報入力
-#form_tagメソッドでcreateアクションに入力情報を渡します。
= form_tag(credit_cards_path, method: :post, id: "charge-form", class: "details", name: "inputForm") do
.number-details
.card-number カード番号
%span.must_check 必須
.number
= text_field_tag 'payment_card_no', "", class: 'cardnumber', id: "payment_card_no", placeholder: '半角数字のみ', type: "text", maxlength: "16"
-# 事前にassets/imagesにcardsファイルを作成、中に各カード会社の画像を入れておき、呼び出す。
.image
= image_tag(image_path('cards/visa.png'), class: 'visa')
= image_tag(image_path('cards/master.png'), class: 'master')
= image_tag(image_path('cards/jcb.png'), class: 'jcb')
= image_tag(image_path('cards/amex.png'), class: 'amex')
= image_tag(image_path('cards/diners.png'), class: 'diners')
= image_tag(image_path('cards/discover.png'), class: 'discover')
.expirationdate
.expirationdate__details
.date 有効期限
%span.must_check 必須
.expirationdate__choice
.month
%select#payment_card_month.card-default{name: "payment_card_month", type: "text"}
%option{value: "1"} 01
%option{value: "2"} 02
%option{value: "3"} 03
%option{value: "4"} 04
%option{value: "5"} 05
%option{value: "6"} 06
%option{value: "7"} 07
%option{value: "8"} 08
%option{value: "9"} 09
%option{value: "10"} 10
%option{value: "11"} 11
%option{value: "12"} 12
.month-details 月
.year
%select#payment_card_year.card-default{name: "payment_card_year", type: "text"}
%option{value: "2020"} 20
%option{value: "2021"} 21
%option{value: "2022"} 22
%option{value: "2023"} 23
%option{value: "2024"} 24
%option{value: "2025"} 25
%option{value: "2026"} 26
%option{value: "2027"} 27
%option{value: "2028"} 28
%option{value: "2029"} 29
%option{value: "2030"} 30
.year-details 年
.securitycode
.securitycode__details
.securitycode-details__title セキュリティコード
%span.must_check 必須
.securitycode__cardsecurity
= text_field_tag "payment_card_cvc", "", type: 'text', class: 'securitycode__cardsecurity__form', id: "payment_card_cvc", maxlength: "4", placeholder: 'カード背面4桁もしくは3桁の番号'
.card-question カード裏面の番号とは?
.add
= submit_tag "登録する", class: "add__btn", id: "payment_card_submit-button"
scssは省略で、、、
一番重要! トークン化処理のためのpayjp.js
記載
実装は提供されている
クレジットカード情報をトークン化するpayjp.jsの使い方
を参考に
ですが正直言ってだいぶ分かりにくいです、、、
ちなみにjQueryを利用してますので、未設定の場合はこちらを参考に導入お願いします!
参考にさせていただいた記事: RailsでjQueryを使えるようにする方法
window.addEventListener('DOMContentLoaded', function(){
//id名が"payment_card_submit-button"というボタンが押されたら取得
let submit = document.getElementById("payment_card_submit-button");
Payjp.setPublicKey('pk_test_###'); //公開鍵の記述(ご自身の公開鍵コードを記述しよう!)
submit.addEventListener('click', function(e){ //ボタンが押されたらトークン作成開始。
e.preventDefault(); //ボタンを1度無効化
let card = { //入力されたカード情報を取得(id名の記載ミスに注意!)
number: document.getElementById("payment_card_no").value,
cvc: document.getElementById("payment_card_cvc").value,
exp_month: document.getElementById("payment_card_month").value,
exp_year: document.getElementById("payment_card_year").value
};
Payjp.createToken(card, function(status, response) { // トークンを生成
if (status === 200) { //成功した場合(status === 200はリクエストが成功している状況です。)
//データを自サーバにpostしないようにremoveAttr("name")で削除
$(".number").removeAttr("name");
$(".cvc").removeAttr("name");
$(".exp_month").removeAttr("name");
$(".exp_year").removeAttr("name");
$("#charge-form").append(
$('<input type="hidden" name="payjp_token">').val(response.id)
); //取得したトークンを送信できる状態にします
document.inputForm.submit();
alert("登録が完了しました"); //正常処理完了確認用。createビューがあればつけなくてもOKかな
} else {
alert("カード情報が正しくありません。"); //エラー確認用
}
});
});
});
ちなみにこちらの実装が一番難しいと思うので、複数のサイトを比較して実装を進めることをおすすめします。
参考にさせていただいた記事:
Railsフリマアプリ payjpを使ってクレジットカードを登録・削除
Pay.jpをRailsで!【登録・削除・購入】
Payjpでクレジットカード登録と削除機能を実装する(Rails)
[HowTo]Pay.jpを用いたクレジットカードの登録機能実装について/カスタムフォーム版
これにより、クレジットカード新規登録、登録内容入力(newメソッド
)、入力内容をトークン化(payjp.js
での処理)、トークン化された入力内容がuser_idと紐づいてcredit_cardsテーブルに登録される(createメソッド
)処理が実装されました!
おまけ createビューの記述
最後に、問題なく登録が完了された場合のcreateビューを記述して完成です。
(特にこだわり等なければ、redirect_to
等でマイページやトップページに遷移させても問題ないです。)
createビューの表示例
createアクション
のviewを記載
(例によって部分テンプレートを使っています。)
.create
.create__frame
.create__frame__message
登録が完了しました。
%ul.create__frame__btns
-# マイページに戻るパスを指定
%li.my_page_link
= link_to "マイページに戻る", users_path(current_user.id), class: "my_page_link__btn"
-# のちに実装する、登録クレジットカード詳細表示(showアクション)に行くパスを指定
%li.credit_cards_index_link
= link_to "登録カード一覧", credit_card_path(current_user.id), class: "credit_cards_index_link__btn"
###クレジットカード新規登録機能実装 完了!!
最後に
以上でクレジットカードの新規登録機能の実装は完成です!
さらに発展させると、ユーザー登録時にクレジットカード登録機能を差し込むこともできそうですね。
あと、何度も言いますが、登録テスト時には必ず、テストカードの番号での登録をお願いしますね!
次回は、「クレジットカード編集・削除 機能」の実装を行います。
参考リンク
- 公式サイト
- 参考にさせて頂いたQiita記事
- 主に
payjp.js
(トークン化処理)の記述で参考にしたサイト - その他の機能実装時の参考サイト