Railsで　Payjp.js V2　でクレジットカード登録機能実装　フリマアプリ

#　概要
payjp.jsを使用し、カスタマイズ可能なv2での実装の記事が全くなかったので
共有したと思います。
v1での実装記事は沢山のあったのですが、、、、


>###payjp.js v2をβ提供しました
>カード情報のトークン化機能を提供しております payjp.js につきまして、最新のPCI-DSSに準拠した payjp.js >v2をこの度β提供いたしました。

> ###payjp.js v2 とは
>payjp.js v2は、従来のカード情報のトークン化機能に加えて、最新のPCI-DSSに準拠したカード情報入力フォーム>生成ライブラリとなります。

>機能や詳細については、リファレンスおよびガイドをご覧ください。 また、デモも複数用意しております。

>###移行のお願い
>現行の payjp.js v1につきましては、v2の本リリース（4月上旬を予定）と同時に、新規での利用を非推奨とさせてい>ただく予定となっております。

>v1をすでにご利用の加盟店様におかれましては大変お手数ですが、payjp.js v2への移行をお願いいたします。

>v1からの移行手順につきましては、あらためて本ブログにて記事を公開いたします。 移行の詳細なスケジュールにつき>ましても、別途お知らせいたしますのでご了承ください。

>今後ともPAY.JPをどうぞよろしくお願いいたします。
> 参照：[PAY.JP　Blog](http://payjp-announce.hatenablog.com/?page=1587434400)

とあったのでこれからは、こちらが推奨となるということなので少しでも
皆様のお力になれればと思って実装できたので書き記しておきます。
[PAY.JP API 利用ガイド | PAY.JP](https://pay.jp/docs/cardtoken)
をご覧いただいてから実装するとかなり理解しやすいかと思います。

↑
駆け出しエンジニアなので間違っているところあれば修正いたしますので
なんなりとご意見くださいませ:point_up:

##バージョン情報
- ruby 2.6.5
- Rails 6.0.3.2


目次
1.Payjpのアカウントを作成
2.APIを確認
3.PayjpとdotenvのGemをinstall
4.payjp.jsを読み込めるようにする
5.保存するテーブルを作成
6.コントローラーを作成
7.カードの登録画面を作成
8.javascriptファイルを作成
9.ルーティングを作成
10.カードを登録


## 1.Payjpのアカウントを作成
[Payjp](https://pay.jp/)のサイトでアカウントを作成します。




## 2.APIを確認
ログイン後ダッシュボードのAPIより確認しますす。
今回はテストモードでの実装なので、**テスト秘密鍵**と**テスト公開鍵**を使用します。
![b36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664372/8d3f412e-f859-caac-e14f-9289b04e21bd.png)




## 3.PayjpとdotenvのGemをinstall
payjpのgemを設置します

```ruby:Gemfile
gem 'payjp'
gem 'dotenv'
```
Gemfileに記述したらインストールです。

```terminal:terminal
$  bundle install
```

touch コマンドで.envを作成

```terminal:terminal
$ cd 作成したアプリのディレクトリ
$ touch .env　
```

作成ができたら先ほどのAPIを.envの記述
ここで`'pk_test_000000000000000000000000'`と記述すると本番環境で動かないことがあるかも、、

```ruby
PAYJP_PRIVATE_KEY=pk_test_000000000000000000000000
PAYJP_SECRET_KEY=sk_test_000000000000000000000000
```

#### Git を使用している場合は、以下を記述しリモートリポジトリにPushしないようにしてください！
```terminal:.gitnore
.env
```

## 4.payjp.jsを読み込めるようにする
**★Hamlで記述してます　hamlの導入方法はこちらを↓**
[Railsでhamlを導入する！ | Qiita](https://qiita.com/mitsumitsu1128/items/f1b0b047553fde49bbc1)

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

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

```


## 5.保存するテーブルを作成
下記コマンドでpayjpのデータを保管するデータベースのテーブルを作成します

```terminal:terminal
$ rails g model Card user_id:integer customer_id:string card_id:string
```

コマンドするとdbにマイグレーションファイルができているので中身を確認する

```ruby:db/migrate/2020800********_create_cards.rb
class CreateCards < ActiveRecord::Migration[6.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
```


マイグレーションをする。

```terminal:terminal
$ rails db:migrate
```

カード情報そのものをデーターベースに保存することは禁止されていますので、
payjpに保管されている情報を顧客idやカードidで呼び出すことで情報取得ができます。
>[改正割賦販売法](http://www.meti.go.jp/policy/economy/consumer/credit/kappuhannbaihounoichibuwokaiseisuruhouritsu.pdf) 

>[カード情報非通過化対応](http://payjp-announce.hatenablog.com/entry/2017/11/10/182738)のお願い

## 6.  コントローラーを作成

下記のコマンドでコントローラーを作成します

```terminal:terminal
$ rails g controller card
```

```ruby:pp/controllers/card_controller.rb
class CardsController < ApplicationController

  require 'payjp' #これでpajpのメソッドが使用できます

  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_SECRET_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,        # ここでcurrent_user.idがいるので、前もってsigninさせておく
        customer_id: customer.id,        # customerは上で定義
        card_id: customer.default_card  # .default_cardを使うことで、customer定義時に紐付けされたカード情報を引っ張ってくる ここがnullなら上のcustomerのcard: params['payjp_token']が読み込めていないことが多い
      )
      if @card.save
        redirect_to action: "show"
      else
        redirect_to action: "pay"
      end
    end
  end



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

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

end
```

## 7.カードの登録画面を作成
**ここからがv2で少しv1を違います！！！！**

```haml:new_credit.html.haml
      .form-group
        %p#number-form.payjs-outer
        %p#expiry-form.payjs-outer
        %p#cvc-form.payjs-outer
      .form-group
        = form_with url: pay_cards_path, method: :post,id: "card_form" do |f|
          #card_token
          = f.submit "登録する", class:"btn", id: "info_submit"

```

これだけであとは、javascriptにpay.jsを記載すれば以下のelementsが非同期通信で現れます！
![スクリーンショット 2020-08-26 11.25.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664372/c7c6f8df-2fb1-545f-2062-e8a232be37c6.png)


## 8.javascriptファイルを作成
[Rails でjQueryが使用できる状態](https://qiita.com/ngron/items/95846bd630a723e00038)にしてもらい以下を記述
（jsを記述する前に[payjp.js v2 ガイド](https://pay.jp/docs/payjs-guidance)と[payjp.js v2 リファレンス](https://pay.jp/docs/payjs)を読んでから以下の記述に入ると理解がしやすいです:point_up:）

```js:app/assets/javascripts/pay.js
$(window).bind("load", function(){ 
  if (document.URL.match(/cards/)){
  //　　↑　URlに/crads/がある時のみ発火するように

    var payjp = Payjp('pk_test_*************0')
     //　↑公開鍵を登録し、起点となるオブジェクトを取得します

    var elements = payjp.elements();
　　　//　↑elementsを取得します。

    var numberElement = elements.create('cardNumber');
    var expiryElement = elements.create('cardExpiry');
    var cvcElement = elements.create('cardCvc');
　　// ↑　elementを生成します

    numberElement.mount('#number-form');
    expiryElement.mount('#expiry-form');
    cvcElement.mount('#cvc-form');
　　　// ↑　elementをDOM上に配置します

    var submit_btn = $("#info_submit");
    submit_btn.click(function (e) {
      e.preventDefault();
      payjp.createToken(numberElement).then(function (response) {
　　　　//  ↑↑　ここでトークンを作成　// createTokenの引数には任意のElement1つを渡します

        if (response.error) {  //  通信に失敗したとき
          alert(response.error.message)
          regist_card.prop('disabled', false)
        } else {
          alert("登録が完了しました");
          $("#card_token").append(
            `<input type="hidden" name="payjp_token" value=${response.id}>
            <input type="hidden" name="card_token" value=${response.card.id}>`
          );
          $('#card_form')[0].submit();
        　 //  ↑↑　ここでtype='hidden'にしてsubmitにtokenを乗せています

          $("#card_number").removeAttr("name");
          $("#cvc-from").removeAttr("name");
          $("#exp_month").removeAttr("name");
        　$("#exp_year").removeAttr("name");
　　　　　　//  ↑↑　ここでremoveAttrで記述を削除してます
        };
      });
    }); 
  }
});

```
## 8.確認兼削除画面を作成

登録ができたら リダイレクトで card#show アクションが動くので
確認兼削除画面を用意します。


```haml:app/cards/show.html.haml

.creditShow
  %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(delete_cards_path, method: :post, id: 'charge-form',  name: "inputForm") do
    %input{ type: "hidden", name: "card_id", value: "" }
    %button 削除する

```

![スクリーンショット 2020-08-26 11.56.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664372/4e2657e2-0306-24b2-494c-ee4252de2622.png)


## 9. ルーティングを作成
アプリの仕様によって変わってくるのですが、一旦実装できた時の記述を共有させていただくのでアレンジしてください

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



これでroute,MVCの記述が終わったので登録できると思います。

## 10.カードを登録
テストモードでの登録は、
[payjpのテストカード](https://pay.jp/docs/cardtoken)こちらに記載のある

- カード番号: 4242424242424242
- 有効期限: 12/20
- CVC: 123
- カード名義: YUI ARAGAKI

で　http://localhost:3000/cards/new/  で登録してみてください:relaxed:
登録できれば、こちら→[ダッシュボードの顧客](https://pay.jp/d/customers)
に反映されます！


#### 参考記事
[PAY.JP API](https://pay.jp/docs/api/?ruby)
 [Payjpでクレジットカード登録と削除機能を実装する(Rails)｜Qiita](https://qiita.com/takachan_coding/items/f7e70794b9ca03b559dd)
[RailsでjQueryを使えるようにする方法｜Qiita](https://qiita.com/ngron/items/95846bd630a723e00038)
[RailsでPayjpを使った購入機能を実装する｜Qiita](https://qiita.com/suzy1031/items/7964829086eb929471a6)
[【Rails】PAYJPを用いた決済機能の実装手順を簡単にまとめてみた](https://techtechmedia.com/payjp-rails/)