[Rails]Pay.jpを利用したクレジット決済機能実装　③　~クレジットカード詳細表示・削除~

## はじめに
例によって、某プログラミングスクールの最終課題である、フリマアプリのクローンサイト作成において、購入機能実装時にPay.jpを利用したので、健忘録としてここに記す。
今回は「クレジットカード詳細表示・削除」の実装に取り掛かります。


## バージョン情報
ruby '2.5.1'
Rails '5.2.4.2'

## 実装の流れ
1. [実装の準備・APIの導入](https://qiita.com/Shunsuke_i_21/items/19c8326282510ae30eab)
2. [モデルの作成・クレジットカード登録](https://qiita.com/Shunsuke_i_21/items/cd638e6aebba126683f1)
3. <font color="DeepPink">クレジットカード詳細表示・削除</font>　←　今回の実装内容
4. [クレジットカード購入(決済)機能](https://qiita.com/Shunsuke_i_21/items/8745c245205fa182f974)

## 前提条件として
* 記載はhaml記法で
 * [私の参考にしたrailsにhamlを導入するやり方はこちら、、](https://qiita.com/MitsuguSueyoshi/items/f1b0b047553fde49bbc1)
* ユーザー登録機能として、gemの``devise``を利用しています。 なので``current_user``などの``devise``のメソッドが随所に出てきます
 * 参考記事: [【Rails】deviseを導入してみる](https://qiita.com/Hal_mai/items/350c400e8763ce0487a3) 

## 今回の実装機能のダイジェスト
### クレジットカード詳細表示から削除はこんな感じ
[![Image from Gyazo](https://i.gyazo.com/95ccd895df93ee6cddcc762aa2bb8f15.gif)](https://gyazo.com/95ccd895df93ee6cddcc762aa2bb8f15)

* クレジットカード詳細表示画面上で、登録クレジット会社のロゴ画像、カード番号末尾４桁、有効期限が表示される。
* 削除ボタンを押すと、登録情報が削除される

<font color="blue">**前置きはこれくらいで、いよいよ実装！**</font>

## **いよいよ実装！** まずはコントローラーの記載
まずはコントローラーの記載を行います。
詳細表示機能は``showアクション``で、削除機能は``destroyアクション``で定義します。

```ruby:controllers/credit_cards_controller.rb
  require "payjp" # PAYJPとやり取りするために、payjpをロード
 
  def new
    # 前回のnewアクションに追記
    # すでにクレジットカード登録されている場合は、showアクションにリダイレクト
    @card = CreditCard.where(user_id: current_user.id)
    redirect_to credit_card_path(current_user.id) if @card.exists?
  end

  # ここのcreateメソッドは前回と同じ
  def create
    Payjp.api_key = Rails.application.credentials.dig(:payjp, :PAYJP_SECRET_KEY)

    if params["payjp_token"].blank?
      redirect_to action: "new", alert: "クレジットカードを登録できませんでした。"
    else
      customer = Payjp::Customer.create(
        email: current_user.email,
        card: params["payjp_token"],
        metadata: {user_id: current_user.id}
      )
      @card = CreditCard.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
      if @card.save
      else
        redirect_to action: "create"
      end
    end
  end
  
  def show
    # ログイン中のユーザーのクレジットカード登録の有無を判断
    @card = CreditCard.find_by(user_id: current_user.id)
    if @card.blank?
      # 未登録なら新規登録画面に
      redirect_to action: "new" 
    else
      # 前前回credentials.yml.encに記載したAPI秘密鍵を呼び出します。
      Payjp.api_key = Rails.application.credentials.dig(:payjp, :PAYJP_SECRET_KEY)
      # ログインユーザーのクレジットカード情報からPay.jpに登録されているカスタマー情報を引き出す
      customer = Payjp::Customer.retrieve(@card.customer_id)
      # カスタマー情報からカードの情報を引き出す
      @customer_card = customer.cards.retrieve(@card.card_id)

      ##カードのアイコン表示のための定義づけ
      @card_brand = @customer_card.brand
      case @card_brand
      when "Visa"
        # 例えば、Pay.jpからとってきたカード情報の、ブランドが"Visa"だった場合は返り値として
        # (画像として登録されている)Visa.pngを返す
        @card_src = "visa.png"
      when "JCB"
        @card_src = "jcb.png"
      when "MasterCard"
        @card_src = "master.png"
      when "American Express"
        @card_src = "amex.png"
      when "Diners Club"
        @card_src = "diners.png"
      when "Discover"
        @card_src = "discover.png"
      end
      
      #  viewの記述を簡略化
      ## 有効期限'月'を定義
      @exp_month = @customer_card.exp_month.to_s
      ## 有効期限'年'を定義
      @exp_year = @customer_card.exp_year.to_s.slice(2,3)
    end
  end

  def destroy
    # ログイン中のユーザーのクレジットカード登録の有無を判断
    @card = CreditCard.find_by(user_id: current_user.id)
    if @card.blank?
      # 未登録なら新規登録画面に
      redirect_to action: "new"
    else
      # 前前回credentials.yml.encに記載したAPI秘密鍵を呼び出します。
      Payjp.api_key = Rails.application.credentials.dig(:payjp, :PAYJP_SECRET_KEY)
      # ログインユーザーのクレジットカード情報からPay.jpに登録されているカスタマー情報を引き出す
      customer = Payjp::Customer.retrieve(@card.customer_id)
      # そのカスタマー情報を消す
      customer.delete
      @card.delete
      # 削除が完了しているか判断
      if @card.destroy
      # 削除完了していればdestroyのビューに移行
      # destroyビューを作るのが面倒であれば、flashメッセージを入れてトップページやマイページに飛ばしてもOK

      else
        # 削除されなかった場合flashメッセージを表示させて、showのビューに移行
        redirect_to credit_card_path(current_user.id), alert: "削除できませんでした。"
      end
    end
  end
```
(例によって、フラッシュメッセージをしれっと入れてます)
参考にした記事: [【Rails】flashメッセージを使用して簡易メッセージを表示させる詳しい方法と解説](https://qiita.com/dice9494/items/2a0e92aba58a516e42e9)

変更、追記内容としては

* newメソッドにクレジットカード登録済みの際にshowアクションに移るように定義
* (詳細表示機能として)showメソッドの定義。その際に
    * viewで表示するクレジットカードのブランド画像を定義
    * viewで表示するクレジットカード情報の有効期限の年と月を定義
* (削除機能として)destroyメソッドを定義 

です。

### ついでにルーティングも設定しておく
```ruby:config/routes.rb
Rails.application.routes.draw do

# したの方に追記　:show, :destroyを追加で記述
  resources :credit_cards, only: [:new, :create, :show, :destroy] do
  end
end
```

これでパスが生成されたので、該当リンクに貼り付けます。

## 続いて、ビューの記載
ちなみに部分テンプレートを使用してます(ファイル名を参照！)。

### showビューの記載
```ruby:views/credit_cards/show/_show.html.haml
.show
  .show__frame
    .show__frame__title
      登録クレジットカード情報
    .credit_card__list
      .credit_card__list__title
        クレジットカード一覧
      .credit_card__list__frame
        .credit_card_info
          .credit_card_info__brand
            # showメソッドで定義した@card_srcを呼び出し
            # 画像をcardsというフォルダを作り、入れておく
            = image_tag "cards/#{@card_src}", class: "credit_card_info__brand__img", alt: @card_brand
          .credit_card_info__numbers
            .number
              # Pay.jpから取得したカード番号の末尾４桁を取得
              = "**** **** **** " + @customer_card.last4
            .expiration_date
              .expiration_date__title
                有効期限
              .expiration_date__info
                # showメソッドで定義した有効期限の年と月を取得
                = @exp_month + " / " + @exp_year
        .destroy__function
          .destroy__function__link
            # 削除ボタンを作成、押すとdestroyメソッドが働くように
            = link_to credit_card_path, method: :delete, class: "destroy__function__link__btn" do 
              削除する
      .payment-details
        = link_to "支払い方法について >", "", class: "payment-details__btn"
```
(SCSSはお好みで、、、)
表示例としてはこんな感じ
[![Image from Gyazo](https://i.gyazo.com/4ba9d3da0098607087ca78a624888e11.png)](https://gyazo.com/4ba9d3da0098607087ca78a624888e11)

## (お好みで実装)destroyビューの記載
```ruby:views/credit_cards/destroy/_destroy.html.haml
.destoroy
  .destoroy__frame
    .destoroy__frame__message
      削除が完了しました。
    %ul.destoroy__frame__btns
      %li.credit_card_new_link
        = link_to "クレジットカード新規登録", new_credit_card_path, class: "credit_card_new_link__btn"
      %li.my_page_link
        = link_to "マイページに戻る", users_path(current_user.id), class: "my_page_link__btn"
```
特に言うことはありません、、、、
クレジット新規登録(``newアクション``へのパス)をつけておけば、編集機能っぽくなるのかな？

表示例としてはこんな感じ
[![Image from Gyazo](https://i.gyazo.com/03429d5a2c607cf473ecf37b250e0556.png)](https://gyazo.com/03429d5a2c607cf473ecf37b250e0556)

###<font color="blue">クレジットカード詳細表示・削除機能　実装完了！！</font>

## 最後に
以上でクレジットカードの詳細表示・削除機能の実装は完成です！
前回の新規登録機能よりかは難易度が下がったのではないでしょうか。

次回は、「[クレジットカード購入(決済)機能](https://qiita.com/Shunsuke_i_21/items/8745c245205fa182f974)」の実装を行います。

## 参考リンク
* 公式サイト
    * [公式リファレンス](https://pay.jp/docs/payjs)
    * [公式ガイド](https://pay.jp/docs/api/?ruby#payjp-api)
* 参考にさせて頂いたQiita記事
    * [【Ruby on Rails で簡単！】PAY.JPを利用したクレジットカード決済の導入](https://qiita.com/mylevel/items/7462ca28260581509d19)
    * [Payjpでクレジットカード登録と削除機能を実装する(Rails)](https://qiita.com/takachan_coding/items/f7e70794b9ca03b559dd)
    * [Pay.jpをRailsで！【登録・削除・購入】](https://qiita.com/Masataka_Sugi/items/57b68eb19de0c014ef12)
* その他の機能実装時の参考サイト
    * [Railsでhamlを導入する！](https://qiita.com/MitsuguSueyoshi/items/f1b0b047553fde49bbc1)
    * [【Rails】deviseを導入してみる](https://qiita.com/Hal_mai/items/350c400e8763ce0487a3) 
    * [【Rails】flashメッセージを使用して簡易メッセージを表示させる詳しい方法と解説](https://qiita.com/dice9494/items/2a0e92aba58a516e42e9)