[Rails] クレジット決済機能をPayjpで実装(payjp.js)

**RailsでPay.jpを導入する方に向けての記事になります。**
決済機能実装としてPayJpを導入したので備忘録として書いていきます。


## APIキーを取得
まずはじめに[Payjpのサイト](https://pay.jp/d/settings)へ行きAPIへのキーを取得します。
今回はローカル環境で動かしていくので必要な**鍵は「テスト秘密鍵」と「テスト公開鍵」になります**
<img width="1285" alt="payjp.png" src="https://qiita-image-store.s3.amazonaws.com/0/351739/a7f04a34-2fe4-c4a6-c845-8557ac9f41b6.png">

Payjpを導入するにあたりcheckoutとpayjp.js（カスタムフォーム)での2つの方法があります。
### 「checkout」
**チェックアウトはscriptタグを１行追加する事でデザインされた決済フォーム、カード情報のバリデーション、カード情報をトークン化を行うフォームを生成するライブラリになります。**
checkoutは決済のフォームをカスタマイズすることは出来ませんがscriptタグを１行挿れるだけで実装が可能になります。
以下がチェックアウトの決済フォームです。
<img width="1174" alt="スクリーンショット 2019-04-05 12.38.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/351739/306bb480-87c1-6960-c1e4-9ae0af98dd4d.png">

**注意事項**
チェックアウトは、HTMLドキュメントの読み込みを起点として決済フォームを構築するため、各種のシングルページアプリケーションフレームワークやRuby on Railsのturbolinks機能など、 通常の画面遷移やドキュメント読み込みとは違う方法を利用する場合に、正しく表示されないことがあります。 この場合は payjp.js を利用して決済フォームをご用意いただくことをご検討ください。
>　引用　[Checkout](https://pay.jp/docs/checkout)

### 「Payjp.js」
**今回実装していく**のはこちらのPayjpjsです。
特徴として
**-　カード情報をトークン化のみに特化**
**-　デザインや挙動を好きなものにカスタマイズ可能**

先ほどのcheckoutとは異なり自分でフォームを作成しjsファイルで入力されたカード情報を取得しPayjpのサーバーと通信を行いトークンを取得するという流れになります。
>　引用　[payjp.js](https://pay.jp/docs/payjs)

##導入

コードを交えて全体の流れを説明していきます。

はじめにこれから行なっていく全体的な流れを説明していきます。
###1.gemを導入
###2.カード情報を取得するためのフォームを作成
###3.scriptタグを読み込み
###4.jsファイルで入力された情報を取得しtokenを作成
###5.作成されたトークンをcontrollerで受け取る


##gemの導入
今回はRailsを使っての実装となるのでpayjpのgemを入れましょう。
Github　→　[PAY.JP for Ruby](https://github.com/payjp/payjp-ruby)

##フォーム作成
顧客がカード情報を入力するためのフォームを作成します。
説明のため公式にあるフォームを使用しています。
下のコードでaction="/pay"としていますがアクションの指定はPOSTを送りたいURLをrake routesで確認し指定してください。
<img width="853" alt="スクリーンショット 2019-04-05 13.18.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/351739/c2a1260a-5dd9-6c72-4daa-7083c3a1881f.png">
このような場合であれば action="/credits"となります。


```haml:customform.html.haml
= form_tag("/pay", method: :POST, id: "charge-form") do
  %h4 支払い
  %label カード番号
    %input{maxlength: "16", type: "text", class: "number", id: "payment_card_no" name: "number", placeholder: "カード番号"}
  %label CVC
    %input{type: "text", class: "cvc", id: "cvc_code", name: "cvc", maxlength: "3", placeholder: "CVC"}
  %label 有効期限
    %input{type: "text", class: "exp_month", id: "card_expire_mm",  name: "exp_month", maxlength: "2", placeholder: "月"}
    %input{type: "text", class: "exp_year", id: "card_expire_yy", name: "exp_year", maxlength: "4",  placeholder: "年"}
```

##scriptタグの読み込み
フォームの作成が完了したらscriptタグからpayjp.jsを読み込む必要があるのでappication.html.hamlに記入しましょう。
payjp.jsライブラリは[https://js.pay.jp](https://js.pay.jp)にホストされているので、このドメインを読み込んで使います。


```haml:application.html.haml
!!!
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title example
    %script{:src => "https://js.pay.jp/", :type => "text/javascript"} //追加する一文になります。

```
これを読み込んであげないと以下のようなエラー文が出てしまいます。
<img width="362" alt="スクリーンショット 2019-04-06 13.52.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/351739/bf5febbb-3d38-212d-446f-11352d88c240.png">

##jsファイルで入力された情報を取得しtokenを作成
**payjp.jsではトークンを作成してしまえば後はコントローラーで受け取るだけなので作成方法さえ分かってしまえば後はスムーズに行くはずです！**

```javascript:payjp.js
$(document).on('turbolinks:load', function() {
  var form = $("#charge-form");
  Payjp.setPublicKey('pk_test_xxxxxx1212111'); //(自身の公開鍵)

  $("#charge-form").on("click", "#submit-button", function(e) {
    e.preventDefault();
    form.find("input[type=submit]").prop("disabled", true);
    var card = {
        number: parseInt($("#payment_card_no").val()),
        cvc: parseInt($("#cvc_code").val()),
        exp_month: parseInt($("#card_expire_mm").val()),
        exp_year: parseInt($("#card_expire_yy").val())
    };
    Payjp.createToken(card, function(status, response) {
      if (stauts == 200) {
        $(".number").removeAttr("name");
        $(".cvc").removeAttr("name");
        $(".exp_month").removeAttr("name");
        $(".exp_year").removeAttr("name");

        var token = response.id;
        $("#charge-form").append($('<input type="hidden" name="payjp_token" class="payjp-token" />').val(token));
        $("#charge-form").get(0).submit();
        
      }
      else {
        alert("error")
        form.find('button').prop('disabled', false);
      }
    });
  });
});
```
**Payjp.setPublicKey('pk_test_xxxxxx1212111');**
これを記述しないとPayjpサーバーと通信が行われずトークンが発行されないので自分のAPIキーを確認しましょう。
[自身のテスト公開鍵を確認](https://pay.jp/d/settings)

var cardのところでparseIntを使用している理由はnumber, cvcは文字列になっているのでそれを整数に変換し数値として取得しています。

**createToken(card, calback)**
PAY.JPのサーバーと通信し、カード情報の認証を行い、トークンを作成します。

```javascript
Payjp.createToken(card, function(status, response) {
  if (status == 200) {
    // 作成したトークンをサーバーサイドで受け取れる処理
   //response.idでトークンのidを取得できる
  } else {
    // エラーメッセージを表示するなどのエラー処理を記述
  };
});
```


```javascript
$(".number").removeAttr("name");
```
removeさせることでカード情報をparamsの値として含まれないようにしています。
値が含まれていないかを確認したい場合はターミナルを覗いてみましょう。

```javascript
$("#charge-form").append($('<input type="hidden" name="payjp_token" class="payjp-token" />').val(token));
```
**この一文を記述してあげることでコントローラーにトークンIDをparamsとして渡せるようになるわけです。**
通信が成功しstatusが200になった時typeがhiddenとなっているinput要素が追加されるわけです。
これが値として変数tokenを取得しているのでreponse.idがコントローラーでparams[:payjp_token]として受け取ることが可能になります。


最後はe.preventDefault();として停止していたイベントをsubmitで実行しています。


##作成されたトークンをcontrollerで受け取る。

```ruby
Payjp.api_key = 'sk_test_c62fade9d045b54cd76d7036' #シークレットキーは直接書き込まずにdontenv等のGemをインストールし環境変数として呼び出すといいと思います。 例) ENV['PAYJP_SECRET_KEY']
customer = Payjp::Customer.retrieve('cus_4df4b5ed720933f4fb9e28857517')
customer.cards.create(
  card: 'tok_76e202b409f3da51a0706605ac81'
)
```
これは顧客のカードを作成するためのAPIになります。
APIは関数みたいものでありPAY.JP側が提供しているAPIを叩き顧客のカードを作成、カード情報を取得、そして支払いを作成します。


コントローラーの処理ではどのような処理をさせたいかにより記述が異なってくるので今回は**顧客を作成しその顧客のカードを作成していきます。**

```ruby:credits_controller.rb
Payjp.api_key = ENV["PAYJP_SECRET_KEY"] #秘密鍵なので定義した環境変数を入れています。
customer = Payjp::Customer.create(description: 'test') #まずは顧客を作成します。 descriptionは無くても顧客は作成出来ます。
customer.cards.create(card: params[:payjp_token] #カードの作成です。

```
カードを作成すると以下のようなレスポンスが返ってきます。<img width="562" alt="スクリーンショット 2019-04-06 15.16.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/351739/f0b9acfa-0561-a3a6-e69d-8400d1e53472.png">

テストでカードを登録する際は下にあるテストカード番号が記載してあるURLに飛びそちらのカード番号を使ってください。
[テストカードURL](https://pay.jp/docs/testcard)

##最後に
PAY.JPには他にも定期課金などのAPIが用意されていますので気になる方は自身で調べてみてください。
[公式リファレンス for Ruby](https://pay.jp/docs/api/#introduction)

自分はまだプログラミングを学び始めたばかりの初学者なので何かおかしな記述などありましたらコメント欄にてお伝えしていただくと助かります！
ありがとうございました。