はじめに
軽く自己紹介から
TECH::EXPRETというプログラミングスクールに通っております。
53期で活動して、そろそろ終わりに近づいてきましたので、実装した部分くらいは
アウトプットするかーってことで、やります。
テストはやってないので、それ目的の方はごめんなさい。
今回この記事を書く目的は2つほどあります。
1.チームメンバーに学んだ技術の共有の為
なんか作ったらわかりやすいかなーと思ってます
3.アウトプットを通して、今回学んだ内容をしっかり定着させる為
ぶっちゃけ忘れているところが多々あります笑 思い出すためにもしっかり書きます笑
開発環境
ruby 2.5.1
rails 5.2.1
mysql
ゴール
以下のように登録をrails5でできるようにしましょう
- payjpの画面前提準備
deviseでのユーザログイン機能の実装
処理の概要
1) pay.jpのgemをインストール
作業目的:Pay.jpを使用できるようにする為
gem 'payjp'
2) Pay.jpの公式のjavascriptを読み込ませられるようする
作業目的:Pay.jpの公式のjavascriptを読み込ませられるようする為
%script{src: "https://js.pay.jp/", type: "text/javascript"}
3) クレジットカードテーブルを作成する
作業目的: クレジットカード情報を保存するテーブルを作成
Colun | Type | Options | 意味 |
---|---|---|---|
user_id | references | null: false, foreign_key: true | ログインユーザ |
costomer_id | integer | null: false | 顧客ID情報(pay.jpから返ってくるデータ) |
card_id | integer | null: false | カードID情報(pay.jpから返ってくるデータ) |
costomer_id, card_idは、カード情報(16桁のやつ),有効期限年月,セキュリティーコードを渡すとpay.jpから返ってくるデータのこと
class CreateCreditCards < ActiveRecord::Migration[5.2]
def change
create_table :credit_cards do |t|
t.references :user ,foreign_key: true, null: false
t.string :customer_id, null: false
t.string :card_id, null: false
t.timestamps
end
end
end
なんで、DBにカード情報とか保存しないの?っと疑問に持たれる人もいると思いますので、ここで解説
以下のURLを参照していただければわかるのですが、
Pay.jp側の方で、
セキュリティーの観点から
クレジット情報は、勝手にDBに保存するな。俺が管理する。お前らにはIDやるから我慢しろ。っと言われているからなんですよねー
めんどいですが、クレジット情報や購入情報は毎回Pay.jpに問い合わせる必要があります。
4) クレジットカード情報の追加と削除のコントローラを作っていきます
1つのget、3つのpostの実装
GET
- edit
クレジットカードの新規登録画面 - confirmation
クレジットカードを追加するか選択する画面
POST
- create
payjpとCardのデータベース作成を実施します。 - delete
payjpとCardのデータベースを削除する。 - show
DBのCreditCard情報を、payjpに送りcustomer情報を取り出すために実装
class CreditCardController < ApplicationController
before_action :get_user_params, only: [:edit, :confirmation, :show]
before_action :get_payjp_info, only: [:new_create, :create, :delete, :show]
def edit
end
def create
if params['payjp-token'].blank?
redirect_to action: "edit", id: current_user.id
else
customer = Payjp::Customer.create(
email: current_user.email,
card: params['payjp-token'],
metadata: {user_id: current_user.id}
)
@card = CreditCard.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
if @card.save
redirect_to action: "show"
else
redirect_to action: "edit", id: current_user.id
end
end
end
def delete
card = current_user.credit_cards.first
if card.present?
customer = Payjp::Customer.retrieve(card.customer_id)
customer.delete
card.delete
end
redirect_to action: "confirmation", id: current_user.id
end
def show
card = current_user.credit_cards.first
if card.present?
customer = Payjp::Customer.retrieve(card.customer_id)
@default_card_information = customer.cards.retrieve(card.card_id)
else
redirect_to action: "confirmation", id: current_user.id
end
end
def confirmation
card = current_user.credit_cards
redirect_to action: "show" if card.exists?
end
private
def get_payjp_info
if Rails.env == 'development'
Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
else
Payjp.api_key = Rails.application.credentials.payjp[:PAYJP_PRIVATE_KEY]
end
end
end
5) ビュー
作業目的:クレジット情報の、確認と削除、追加のファームを作成する必要があった為。
- confirmation
.main__content
%section.chapter__container
%h2.chapter__head 支払い方法
.payment__main
.payment__list
.payment__list__content
%h3.sub__head クレジットカード一覧
.add__card
.payment__list__content
= link_to edit_credit_card_path(current_user), class: "red__btn", data: {"turbolinks" => false} do
%i
= icon('fas', 'credit-card', class: "card__icon")
クレジットカードを追加する
.not__regist
%span 支払い方法について
- edit
.main__content
%section.chapter__container
%h2.chapter__head クレジットカード情報入力
= form_tag('/credit_card', method: :post, action: "create", id: 'charge-form', name: "inputForm", class: "chapter__container__inner") do
.form__main__container
.form__content
%label.payment__card カード番号
%span.require__form 必須
= text_field_tag "number", "", class: "number input__deafult", placeholder: "半角数字のみ" ,maxlength: "16", type: "text", id: "card_number"
.card__list
.card__list__picture
.form__content.top__margin
%label.payment__card 有効期限
%span.require__form 必須
.select__box.top__margin
.select__box__half
%select.select__default#exp_month{name: "exp_month", type: "text"}
%option{value: ""} --
%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
%i
= icon('fas', 'chevron-down')
%span 月
.select__box__half
.icon
%select.select__default#exp_year{name: "exp_year", type: "text"}
%option{value: ""} --
%option{value: "2019"}19
%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
%i
= icon('fas', 'chevron-down')
%span 年
.form__content.top__margin
%label セキュリティーコード
%span.require__form 必須
= text_field_tag "cvc", "", class: "cvc", placeholder: "カード背面4桁もしくは3桁の番号", maxlength: "4", id: "cvc"
.single__code
.single__code__text
%span.form__question ?
%span カードの裏面の番号とは?
#card_token
= submit_tag "追加する", id: "token_submit", class: "top__margin"
- show
.main__content
%section.chapter__container
%h2.chapter__head 支払い方法
.payment__main
.payment__list
.payment__list__content
%h3.sub__head クレジットカード一覧
.card__payment__list
%form.card__payment__content
.card__list
.card__list__picture
.card__number
= "**** **** **** " + @default_card_information.last4
.expire__date
- exp_month = @default_card_information.exp_month.to_s
- exp_year = @default_card_information.exp_year.to_s.slice(2,3)
= exp_month + " / " + exp_year
= form_tag(delete_credit_card_index_path, method: :post, id: 'charge-form', name: "inputForm") do
%input{ type: "hidden", name: "card_id", value: "" }
%button.delete__button 削除する
.how__not__regist
%span 支払い方法について
6) トークン作成用のJS
作業目的:payjpにデータを送るために実装。入力されたクレジット情報を参考にし、トークンを作成する
document.addEventListener(
"DOMContentLoaded", e => {
if (document.getElementById("token_submit") != null) { //token_submitというidがnullの場合、下記コードを実行しない
Payjp.setPublicKey("pk_test_61fe8dd669a59526fd8542f5"); //ここに公開鍵を直書き
let btn = document.getElementById("token_submit"); //IDがtoken_submitの場合に取得されます
btn.addEventListener("click", e => { //ボタンが押されたときに作動します
e.preventDefault(); //ボタンを一旦無効化します
let card = {
number: document.getElementById("card_number").value,
cvc: document.getElementById("cvc").value,
exp_month: document.getElementById("exp_month").value,
exp_year: document.getElementById("exp_year").value
}; //入力されたデータを取得します。
Payjp.createToken(card, (status, response) => {
if (status === 200) { //成功した場合
$("#card_number").removeAttr("name");
$("#cvc").removeAttr("name");
$("#exp_month").removeAttr("name");
$("#exp_year").removeAttr("name"); //データを自サーバにpostしないように削除
$("#card_token").append(
$('<input type="hidden" name="payjp-token">').val(response.id)
); //取得したトークンを送信できる状態にします
document.inputForm.submit();
alert("登録が完了しました"); //確認用
} else {
alert("カード情報が正しくありません。"); //確認用
}
});
});
}
},
false
);
7) ルーティング
作業目的:最後に、全てのpathを通すためのルーティングを設計します。
resources :credit_card, only: [:create, :show, :edit] do
collection do
post 'delete', to: 'credit_card#delete'
post 'show'
end
member do
get 'confirmation'
end
end
以上で完成です!
とりあえず実装のフローを書いてみました。
感想
商品の購入するためには、クレジット情報が必要になります。
以上の順番で、実装すれば、できるはず!!!
気力があれば、購入のフローも書きたいと思いますー。