payjpを使ってクレジットカード機能を導入しちゃおうってわけ(カード登録編)


今日は涼しいですね。
最近はスーパードライが上手いので毎日1本飲んじゃいますね。
でもやっぱり生ビールが一番ですよね。

さぁて!!!今回はクレジットカード登録編ですわよ!!!
まず大前提としてフリマアプリを作成している想定ってのをわかって頂戴!!

payjpがわからない方はまず導入編をチェケラッ!!
導入編

さぁいくわよ!!!

1 payjpと通信するための鍵を登録する

まずはpayjpのAPIをチェケラ!

(テストも本番も秘密鍵は公開してはいけないので、公開して後悔するなよ!!)
(つまらなすぎて絶望)
(消すの雑だけど、最後の方は武田双雲先生みたいだ。。。。)

現段階で必要なのはテストの秘密鍵と公開鍵。
rails5.2の方はcredentialsへ登録!!

登録の仕方がわからない方は大丈夫アタイの記事を見なよ!!
credentialsの登録方法

名前はなんでも良いけどプライベートキーとか?
ちなみにアタイは

credentials
 :payjp
   :PAYJP_PRIVATE_KEY     = 'sk_test~'
   :PAYJP_KEY             = 'pk_test~'

って感じにしました。

2 続いてRails!!

まずカードモデル作成するわよ。

models/card.rb
 class Card < ApplicationRecord

  belongs_to :user
 #バリデーションはお好みで。

続いてぇマイグレーションファイルぅ

db/migrate/create_cards.rb
class CreateCards < ActiveRecord::Migration[5.2]
  def change
    create_table :cards do |t|
      t.string     :customer_id, null:false
     #customer_idはその名の通り顧客ID.

      t.string     :card_id,     null:false
      t.references :user,        null:false, foreign_key:true
      t.timestamps
    end
  end
end

なんでこんな感じなの?と思ってるかもしれませんがpayjpだとこんな感じに表示されるのですよ。

カード情報をわかりづらくしてくれて保存した値がcard_id
そんでそのcard_idを持っているのがcustomer_id。

そんでcard_idとcustomer_idを持ってDBに保存してuser_idを紐づければ良いってわけ。

オッケーですかな??

3 さーてコントローラーよ!!

cards_controller.rb
class CardsController < ApplicationController
  require "payjp"
  # これでpayjpを読み込むわよ
def new # カードの登録画面。送信ボタンを押すとcreateアクションへ。
    card = Card.where(user_id: current_user.id).first
    redirect_to card_path(@card.id) if card.present?
  end


def create #PayjpとCardのデータベースを作成
   Payjp.api_key = Rails.application.credentials[:payjp][:PAYJP_PRIVATE_KEY]
                               # ここで秘密鍵をセット!!
   if params['payjp-token'].blank?
     redirect_to action: "new"
   else
     # トークンが正常に発行されていたら、顧客情報をPAY.JPに登録します。
     customer = Payjp::Customer.create(
       description: 'test', # 無くてもOK。PAY.JPの顧客情報に表示する概要です。
       email: current_user.email,# これも無くてOK
       card: params['payjp-token'], # 直前のnewアクションで発行され、送られてくるトークンをここで顧客に紐付けて永久保存します。
       metadata: {user_id: current_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 card_path(@card.id)
      else
        redirect_to action: "create"
      end
    end
  end

private

  #user_idが外部キーとしてあるので、まずユーザーがないといけません。
  def set_card
    @card = Card.where(user_id: current_user.id).first if Card.where(user_id:   current_user.id).present?
  end
end

続いてJS!!

payjp.js
document.addEventListener(
  "DOMContentLoaded", (e) => {
    Payjp.setPublicKey("pk_test_0df3d3eb150a3f3dd0f2fc3e");
    const btn = document.getElementById('token_submit'); //IDがtoken_submitの場合に取得されます
    btn.addEventListener("click", (e) => { //ボタンが押されたときに作動します
      e.preventDefault(); //ボタンを一旦無効化します

      //カード情報生成
      const 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 hidden name="payjp-token">').val(response.id)
          ); //トークンを送信できるように隠しタグを生成
          document.inputForm.submit();
          alert("登録が完了しました"); 
        } else {
          alert("カード情報が正しくありません。");
        }
      });
    });
  },false);

これで動かなかったらここを調べてみましょう。

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

ちょっと雑になってしまいましたが、こんな感じ。
補足編とか気が向いたらビューファイルも一緒にだそうかな。

次回は購入実装編でお会いしましょう!!