LoginSignup
189
212

More than 3 years have passed since last update.

Payjpでクレジットカード登録と削除機能を実装する(Rails)

Last updated at Posted at 2019-04-14

はじめに

この記事は2019年はじめにTECHCAMPで勉強していたときに書いたものですが
おかげさまで未だに多くの方に観ていただいています。
いくつか情報が古いものがあるかもしれませんが、
もしお気づきの点があればご指摘いただければ修正しますので
コメント欄か編集リクエストに記載ください!:pray:
(今後見てくださる方の時間の節約にもなりますので)

実装する機能と前提条件

今回、Payjp(Pay.jp)を利用して入力フォームを直接ページ内に設置します。
実装するものとしては下記のとおりです。

  • 自作のカード情報入力フォーム
  • カード情報とユーザーの紐づけ
  • ユーザーとカードの登録と削除
  • 商品の購入次回の記事参照

イメージとしてはこんな感じの入力フォームです。
image.png

もしSDKを使う場合は別記事をご覧いただくかPAY.JP API 利用ガイド | PAY.JPを触るとイメージをつかみやすいと思います。

バージョン情報

  • ruby 2.3.1
  • Rails 5.0.7

前提条件

  • hamlでの記載(gem 'haml-rails')
  • deviseが導入済みでログインができている

→Devise未導入や何もない状態からスタートする場合は、
『Devise導入の設定手順 ~haml使用/pay.jp導入の前準備~ (Rails)』を先に実施ください。

1.Payjpのアカウントを作成しよう

Payjpのサイトでアカウントを作成します。

2.APIを確認しよう

ダッシュボードのAPIより確認ができます。
今回はテストモードでの実装なので、テスト秘密鍵テスト公開鍵を使用します。
スクリーンショット 2019-04-14 16.31.04.png

3.payjpのgemを設置しよう

下記をgemfileに記載しbundle installを実施します。

gem 'payjp'

4.payjp.jsを読み込めるようにしよう

%script{src: "https://js.pay.jp/", type: "text/javascript"}を下記の通り追記します。

app/views/layouts/application.html.haml
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title payjptest
    %script{src: "https://js.pay.jp/", type: "text/javascript"}
    -# このscriptを記載
    = csrf_meta_tags
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
  %body
    = yield

5.テーブルを作成しよう

下記コマンドでpayjpのデータを保管するテーブルを作成します。

rails g model Card user_id:integer customer_id:string card_id:string

テーブルのカラムの紐づけは下記の通りです。

  • user_id ... Userテーブルのid
  • customer_id ... payjpの顧客id
  • card_id ... payjpのデフォルトカードid

(デフォルトカードidはトークンとは違います。ここの理解で結構時間をとってしまいました…)

作成したマイグレーションファイルは下記のとおりです。nullはお好みでつけてください。

db/migrate/20190400000000_create_cards.rb
class CreateCards < ActiveRecord::Migration[5.0]
  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

マイグレーションを実施します。

$ rails db:migrate

ちなみにカード情報そのものを保存することは禁止されていますので、
payjpに保管されている情報を顧客idやカードidで呼び出すことで情報取得や支払いなどに対応します。
カード情報非通過化対応のお願い

6.コントローラーを作成しよう

下記コマンドでコントローラーを作成します。
後ほどビューも2つ(new,show)作るのでそれも付け加えておきます。

$ rails g controller card new show

作成したコントローラーの内容を変更します。

app/controllers/card_controller.rb
class CardController < ApplicationController

  require "payjp"

  def new
    card = Card.where(user_id: current_user.id)
    redirect_to action: "show" if card.exists?
  end

  def pay #payjpとCardのデータベース作成を実施します。
    Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    if params['payjp-token'].blank?
      redirect_to action: "new"
    else
      customer = Payjp::Customer.create(
      description: '登録テスト', #なくてもOK
      email: current_user.email, #なくてもOK
      card: params['payjp-token'],
      metadata: {user_id: current_user.id}
      ) #念の為metadataにuser_idを入れましたがなくてもOK
      @card = Card.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: "pay"
      end
    end
  end

  def delete #PayjpとCardデータベースを削除します
    card = Card.where(user_id: current_user.id).first
    if card.blank?
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      customer.delete
      card.delete
    end
      redirect_to action: "new"
  end

  def show #Cardのデータpayjpに送り情報を取り出します
    card = Card.where(user_id: current_user.id).first
    if card.blank?
      redirect_to action: "new" 
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      @default_card_information = customer.cards.retrieve(card.card_id)
    end
  end
end

コントローラ内のENV["PAYJP_PRIVATE_KEY"]は環境変数でテスト秘密鍵を設定し読み込みます。
私はdotenvを利用していますので、下記のような形で記載しました。

.env
PAYJP_PRIVATE_KEY = 'sk_test_000000000000000000000000'
PAYJP_KEY = 'pk_test_00000000000000000000000'

7.カードの登録画面を作成しよう

今回は登録画面と確認兼削除画面の2つを作成します。デザインはアレンジしてください。
尚、ルーティングがまだなので画面の表示は『10.カードを登録してみよう』までお待ち下さい。

登録画面

app/view/card/new.html.haml
= form_tag(pay_card_index_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %label カード番号
  = text_field_tag "number", "", class: "number", placeholder: "半角数字のみ" ,maxlength: "16", type: "text", id: "card_number"
  %br
  %label 有効期限
  %select#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
  %span 月/
  %select#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
  %span%br
  %label セキュリティコード
  = text_field_tag "cvc", "", class: "cvc", placeholder: "カード背面3~4桁の番号", maxlength: "4", id: "cvc"
  #card_token
  = submit_tag "追加する", id: "token_submit"

image.png

最初、= sectionを使っていたのですがうまく行かなかったため
%optionが連続発生し駄長なコードになっているのはご了承ください…

確認兼削除画面

app/view/card/show.html.haml
%label 登録クレジットカード情報
%br
= "**** **** **** " + @default_card_information.last4
%br
- 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(card_delete_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %input{ type: "hidden", name: "card_id", value: "" }
  %button 削除する

image.png

8.Payjpにデータを送りトークンを取得しよう

提供されているpay.jpのサンプルを参照し一部アレンジしております。

jQueryを使用するので、railsに未設定の場合は設定をしてください。
設定方法はこちら

app/assets/javascripts/payjp.js
document.addEventListener(
  "DOMContentLoaded", e => {
    if (document.getElementById("token_submit") != null) { //token_submitというidがnullの場合、下記コードを実行しない
      Payjp.setPublicKey("pk_test_79ae2d2743199a76f3eb36aa"); //ここに公開鍵を直書き
      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
);

9.ルートを作成しよう

今回はshow,pay,new,deleteの4つのメゾットがあるので下記の通り追記します。
一部はresoursesで設定してもよいかと思います。

config/routes.rb
resources :card, only: [:new, :show] do
  collection do
    post 'show', to: 'card#show'
    post 'pay', to: 'card#pay'
    post 'delete', to: 'card#delete'
  end
end

10.カードを登録してみよう

http://localhost:3000/card/new にアクセスして登録できるか確認してみましょう。

その時、下記のテストカードで登録するようにしてください。
それ以外を打ち込んだ場合はトークンが発行できずはねられてしまいます。
image.png

以上でカード登録から削除まで一通り実装できました。
次回はこれを使って商品支払いを実装します。

参考

189
212
6

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
189
212