【フリマアプリ】PAY.JPでのクレジットカード決済機能について（第３回）　〜運用編（購入）〜

　某スクールにおいて、チーム開発で、フリーマーケットアプリを作成中であり、使用した技術について公開しています。
※初学者のため、ミスや認識違いが多々あると思いますがご了承ください。

# フリマアプリにおいて、PAY.JPを用いたクレジットカード決済機能を実装しました！！

前回記事　

今回の記事は運用編（購入）となります。

それでは、実際にPAY.JPを用いてクレジットカード機能を用いた購入ができるように実装して行きたいと思います。

##カード情報表示

<img width="594" alt="825ca2a1a52d58d1bdafec6ab3d0b05f.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/d2c3ef7b-3050-df76-13cb-874ddcc3ea33.png">



「購入する」ボタンをクリックしたら、**cardsコントローラーのshow**アクションに遷移します。

<img width="500" alt="0b757cba1d9c27d344feafefe81b6d41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/ccce4cb2-59c0-3057-b4fb-43f8070cebf8.png">













遷移先の「購入確認画面」です。ご覧のように、カードの情報が記載されているため、showコントローラーではユーザーに紐づいたカード情報を取得してくる必要があります。

では、showコントローラーを確認してみます。

```ruby:cards_controller
class CardsController < ApplicationController
  require 'payjp'

  before_action :set_item, only:[:show,:pay]
  before_action :take_card, only:[:show,:pay]
  before_action :set_api_key

  def show 
      if @card.blank?
        #登録された情報がない場合にカード登録画面に移動
        flash[:alert] = '購入前にカード登録してください'
        redirect_to cards_path and return
      else
        #保管した顧客IDでpayjpから情報取得
        set_customer
        #保管したカードIDでpayjpから情報取得、カード情報表示のためインスタンス変数に代入
        set_card_information
      end
      if current_user.address == nil
          flash[:alert] = '購入前に住所登録してください'
          redirect_to new_address_path
      end
  end

private

  def set_item
    @item = Item.find(params[:id])
    @address = Address.find_by(user_id:current_user.id)
  end

  def set_api_key
    Payjp.api_key = Rails.application.credentials[:payjp][:PAYJP_PRIVATE_KEY]
    binding.pry
  end

  def set_customer
    @customer = Payjp::Customer.retrieve(@card.customer_id)
  end

  def set_card_information
    @card_information = @customer.cards.retrieve(@card.card_id)
  end

  def take_card
    @card = Card.find_by(user_id: current_user.id)
  end
  
end
```
解説します。
まずは　**before_action :set_item**　が実行されます。これは、商品と配送先住所を引っ張ってくるためで、クレジットカード決済とは直接関係はありません。

次に **before_action :take_card**　が実行されます。
**cardsテーブルから現在のユーザーに紐づくレコードを変数@card**に格納します。（payjp側に保存してる顧客データーではありません。）

```ruby
def show 
 if @card.blank?
   #登録された情報がない場合にカード登録画面に移動
    flash[:alert] = '購入前にカード登録してください'
    redirect_to cards_path and return
 else
```
登録しているカード情報がなければ、カード新規登録画面へ遷移します。
「and　return」は直接関係ないので、後ほど番外で説明します。

```ruby
else
  #保管した顧客IDでpayjpから情報取得
  set_customer
  #保管したカードIDでpayjpから情報取得、カード情報表示のためインスタンス変数に代入
  set_card_information
```
カードが登録されている場合は、set_customerメソッドが呼び出されます。

```ruby
 def set_customer
  @customer = Payjp::Customer.retrieve(@card.customer_id)
 end
```
**@card**の**customer_id**を元に、**Payjpから顧客データー**を取得して、**変数@customer**に格納します。

次に　**set_card_informationメソッド**が呼び出されます。

```ruby
def set_card_information
 @card_information = @customer.cards.retrieve(@card.card_id)
end
```
@customerに紐づく、クレジットカード情報を取得して　**変数@card_information**に格納します。

これにより、クレジットカードの情報を表示することができます。ちなみに、カード情報を表示するhaml部分は以下の通りです。

```haml
-# カード番号
= "**** **** **** " + @card_information.last4
-# 有効期限
　- exp_month = @card_information.exp_month.to_s
　- exp_year = @card_information.exp_year.to_s.slice(2,3)
　= exp_month + " / " + exp_year
```
**Payjp側でlast4というキーに下４桁を格納してくれています。**

##クレジットカードを用いて購入する

「購入する」をクリックしたら、cardsコントローラーのpayアクションへと遷移するようにリンクをはっています

cardsコントローラーのpayアクションを見てみます。

```ruby:cards_controller.rb
class CardsController < ApplicationController
  require 'payjp'

  before_action :set_item, only: [:show,:pay]
  before_action :take_card, only:[:show,:pay]
  before_action :set_api_key
  def pay
    @item.update(buyer_id: current_user.id)
    # 現在のユーザーを購入者に登録
    Payjp::Charge.create(
    :amount => @item.price, 
    :customer => @card.customer_id, 
    :currency => 'jpy', #日本円
   )
    redirect_to item_purchase_index_path(@item.id)
  # 購入確認画面に遷移
  end

private

  def set_item
    @item = Item.find(params[:id])
    @address = Address.find_by(user_id:current_user.id)
  end

  def set_api_key
    Payjp.api_key = Rails.application.credentials[:payjp][:PAYJP_PRIVATE_KEY]
    binding.pry
  end

  def take_card
    @card = Card.find_by(user_id: current_user.id)
  end
  
end
```
解説します。
**before_action :set_item**　で　購入しようとしているItemが@itemに、ユーザーの配送先が@addressに格納されています。クレジットカード購入機能と直接は関係ありません。

**before_action :take_card**
**before_action :set_api_key**
については、showアクションの時と同じです。

```ruby
def pay
  @item.update(buyer_id: current_user.id)
```
現在のユーザーを購入者に登録として、buyer_idカラムに格納します。クレジットカード購入機能と直接は関係ありません。

```ruby
Payjp::Charge.create(
    :amount => @item.price, 
    :customer => @card.customer_id, 
    :currency => 'jpy', #日本円
   )
```
商品の値段や、@cardに紐づく顧客データーを元に、payjp側で決済してくれます。

無事に決済が完了したら、以下のようにpayjp側に反映されます。

<img width="608" alt="115df87f9fd9a7dc1c048027314869b4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/36789dc0-9348-c6bb-1486-e791bca67f3d.png">

以上でクレジットカードを用いた購入機能が実装できました。