PAY.JPでクレジットカードを登録する方法

プログラミング初心者が備忘録のために書いていますのでご注意ください。
今回はカードの登録ができるようにします。

PAY.JPとは
PAY.JPを使うと簡単にクレジットカード登録ができる。
詳しくはpay.jpのサイトを確認してください。
＜[PAY.JPのサイトへ](http://pay.jp)＞

## 認証
[PAY.JP](http://pay.jp)のサイトでユーザー登録。
PAY.JPのAPIを利用するには、ユーザー登録を行い、APIページからAPIキーを取得す必要があります。
ユーザー登録するとテスト用キーと本番用のキーが作成されます。 
サイドバーのAPIのボタンを押すと下のページに移動します。
今回はテストのみ実装するのでテスト秘密鍵とテスト公開鍵を使用します。
![alt](https://pay.jp/theme/images/platform_apikey_update.png)

## 環境変数に書き込む
秘密鍵はコードに直接書かないので環境変数を設定します。
それぞれのPCによって環境変数の書き方は異なると思いますので注意してください。

```:ターミナル
$ vim ~/.bash_profile

iでインサートモード
export PAYJP_PRIVATE_KEY='テスト秘密鍵'
:wqで終了

$ source ~/.bash_profile
```

## gemの導入
実装するアプリのGemfileに書き込み、bundle install。

```ruby:Gemfile
gem 'payjp'
```

## cardsテーブルの作成
クレジットカードを登録するテーブルを作ります。
すでにusersテーブルができている前提で進めています。

```:ターミナル
$ rails g model card
```
```ruby:*****_create_cards.rb(マイグレーションファイル)
class CreateCards < ActiveRecord::Migration[5.2]
  def change
    create_table :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
```
```:ターミナル
$ rails db:migrate
```

## アソシエーションの設定
1人のユーザーが１つのクレジットカードを持てるようにします。

```ruby:user.rb
has_one :card
```
```ruby:card.rb
belongs_to :user
```
## コントローラーの作成
cards_controllerを作り require を記述。

```:ターミナル
$ rails g controller cards
```
```ruby:cards_controller.rb
require 'payjp'
```

## ルーティングの設定
新規クレジットカードを登録するためnewとcreateを作成

```routes.rb
resources :cards, only: [:new, :create]
```

## ビューの作成
超単純なビューの例を作りました。
フォームのみ作成したのでご自分の目的に応じて作成してください。
- カード番号　・　有効期限（月/年)　・　セキュリティーコード
上記の４点を登録できるようにしました。


```new.html.haml
= form_with model: @card, url: cards_path, local: true, html: { name: 'inputForm' } do |f|
  カード番号
  = f.text_field :card_number, id: "card_number"
  有効期限
  = f.select :exp_month, [["01",1],["02",2],["03",3],["04",4],["05",5],["06",6],["07",7],["08",8],["09",9],["10",10],["11",11],["12",12]]
  = f.select :exp_year, [["20",2020],["21",2021],["22",2022],["23",2023],["24",2024],["25",2025],["26",2026],["27",2027],["28",2028],["29",2029]]
  セキュリティーコード
  = f.text_field :cvc, id: 'cvc'
  #card_token
  = f.submit '登録', id: 'token_submit'
```
またapplication.html.hamlに以下の記述を追加する必要があります。

```application.html.haml
%head
  %script{src: "https://js.pay.jp/", type: "text/javascript"}
```

## jsの作成
jsを使って、取得したトークンを送信できるようにします。

```payjp.js
document.addEventListener(
  "DOMContentLoaded", e => {
    if (document.getElementById("token_submit") != null) {
      Payjp.setPublicKey("自分のテスト公開鍵を記述"); 
      let btn = document.getElementById("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"); 
            $("#card_token").append(
              $('<input type="hidden" name="payjp-token">').val(response.id)
            ); 
            document.inputForm.submit();
            alert("登録が完了しました"); 
          } else {
            alert("カード情報が正しくありません。");
          }
        });
      });
    }
  },
  false
);
```

## コントローラーの編集
ビューに合わせてコントローラーを記述します。
save後は移動したいページをご自分で指定してください。
今回はusers_controllerのdoneアクションに飛べるようにしています。

```cards_controller.rb
class CardsController < ApplicationController
  require 'payjp'
  
  def create
    Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    if params['payjp-token'].blank?
      redirect_to action: "new"
    else
      user_id = current_user.id
      customer = Payjp::Customer.create(
      card: params['payjp-token']
      ) 
      @card = Card.new(user_id: user_id, customer_id: customer.id, card_id: customer.default_card)
      if @card.save
        redirect_to controller: :users, action: :done
      else
        redirect_to action: "new"
      end
    end
  end
end
```

## 最後に
何とか登録出来ただけなので細かい設定はできていませんが、参考になる方がいればと思います。
間違いがあるかもしれないのでご了承ください。