RailsでPAY.JP APIを利用する 〜カード登録編〜（payjp.js v2）

# 概要
PAY.JP APIでのカード登録/変更/削除機能実装の覚書です。
今回は取得したトークンからカード情報を登録するまでの手順をまとめていきます。
※簡潔にするため実装のために必要な最低限のコードのみ書いています。

なにか間違い等あれば編集リクエストをいただけると幸いです。

ちなみにpayjp.jsはv1に関する記事は多いですが現行のv2とは異なる部分が多いので注意が必要です。


実装準備編
https://qiita.com/nissy7ok/items/9790ef5ee1dec2863a62
カード登録編←今ここ
https://qiita.com/nissy7ok/items/cea6789fe3b99654e473
カード更新・削除編
https://qiita.com/nissy7ok/items/0ed52954f8fdad772da3

# 環境
```
# OS Version
ProductName:	Mac OS X
ProductVersion:	10.15.7
BuildVersion:	19H2

# Ruby Version
ruby:           2.6.5p114
Rails:          6.0.3.3
```

# 前提条件
PAY.JP APIを用いてトークン情報を取得するところまでできている。
[前回](https://qiita.com/nissy7ok/items/9790ef5ee1dec2863a62)の記事参照。


# 手順
## ビューを編集
JSでエラーメッセージや隠しフォームを仕込むための追記をします。

```haml:_card_form.html.haml
.CardForm
  カード番号
  .CardForm__outer{id: "number-form"}
  有効期限
  .CardForm__outer{id: "expiry-form"}
  セキュリティコード
  .CardForm__outer{id: "cvc-form"}
  #message    -# ここにエラーメッセージが表示されます
  = form_with model: @card, id: "card_form", local: true do |form|
    #card_token   -# ここに隠しフォームが追加されます
    = form.submit "カードを登録", class:"CardForm__button", id: "create_card"

```

## コントローラーを編集
トークンを使用してPAY.JP APIから顧客情報を作成し、Cardテーブルに保存するようにします。
※最低限の記述に削っているので実際は条件分岐をしたほうが良いです。

```ruby:card_controller.rb
class CardController < ApplicationController
  require 'payjp'
  
  def new
  end
  
  def create
    Payjp.api_key = ENV['PAYJP_SECRET_KEY']  # APIを初期化
    customer = Payjp::Customer.create(card: params['payjp_token'])  # 顧客IDから顧客データを作成
    @card = Card.new(
      user_id: current_user.id,          # ユーザーIDと紐付け
      customer_id: customer.id,          # 顧客IDを保存
      card_id: customer.default_card     # 顧客のカード情報を保存
    )
    @card.save
  end
end
```


## JSファイルを編集
カード情報送信ボタンを押すとトークンを使用して顧客IDとカードIDが入った隠しフォームを作成、送信するようにします。

```javascript:card_form.js
// DOM読み込みが完了したら実行
document.addEventListener('DOMContentLoaded', () => {
  // 公開鍵を登録し、起点となるオブジェクトを取得します
  var payjp = Payjp('pk_test_hogehoge')

  // elementsを取得します。ページ内に複数フォーム用意する場合は複数取得ください
  var elements = payjp.elements()

  // element(入力フォームの単位)を生成します
  var numberElement = elements.create('cardNumber', {style: style})
  var expiryElement = elements.create('cardExpiry', {style: style})
  var cvcElement = elements.create('cardCvc', {style: style})
 
 // elementをDOM上に配置します
  numberElement.mount('#number-form')
  expiryElement.mount('#expiry-form')
  cvcElement.mount('#cvc-form')

  // ボタンが押されたらtokenを生成する関数を用意します
  create_card.addEventListener("click", function(e) {
    e.preventDefault();
    payjp.createToken(numberElement).then(function(r) {
      if (r.error) {  // 登録失敗
        document.querySelector('#message').innerText = r.error.message
        regist_card.prop('disabled', false)
      } else {
        $("#card_token").append(  // #card_token部分に隠しフォームを追加
          `<input type="hidden" name="payjp_token" value=${r.id}>
          <input type="hidden" name="card_token" value=${r.card.id}>`
        );
        $("#card_form")[0].submit();  // フォームを送信
      }
    })
  });
});
```

## 

# 参考
結局の所公式APIとガイドが最強です。
ただ読み慣れないうちはQiita等で実際の実装手順を見ながら感覚を掴むと理解が早まると思います。

PAY.JP API リファレンス
https://pay.jp/docs/api/

PAY.JP API 利用ガイド | PAY.JP
https://pay.jp/docs/started
<br>
公式ブログも参考になりますが、情報が古くv1準拠で書かれている場合が多いので注意が必要です。

ごく基本的なPAY.JPの使い方（Ruby編） - PAY.JP Engineering Blog
https://payjp.hatenablog.com/entry/2017/11/21/191916
<br>
その他参考にした記事等

Railsで　Payjp.js V2　でクレジットカード登録機能実装　フリマアプリ - Qiita
https://qiita.com/ta9301/items/6b736390c49c3f40edb6

[HowTo]Pay.jpを用いた商品購入機能実装から商品購入後の設定まで
https://qiita.com/Tatsu88/items/eb420e372077939a4627