25
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Pay.jpを使用してクレジットカード登録削除機能の実装をしてみた

Last updated at Posted at 2019-07-19

はじめに

軽く自己紹介から
TECH::EXPRETというプログラミングスクールに通っております。
53期で活動して、そろそろ終わりに近づいてきましたので、実装した部分くらいは
アウトプットするかーってことで、やります。
テストはやってないので、それ目的の方はごめんなさい。

今回この記事を書く目的は2つほどあります。

1.チームメンバーに学んだ技術の共有の為

なんか作ったらわかりやすいかなーと思ってます

3.アウトプットを通して、今回学んだ内容をしっかり定着させる為

ぶっちゃけ忘れているところが多々あります笑 思い出すためにもしっかり書きます笑

開発環境

ruby 2.5.1
rails 5.2.1
mysql

ゴール

以下のように登録をrails5でできるようにしましょう

  • 実際のビュー
    Image from Gyazo
  • Sequel Pro の CreditCardの画面
スクリーンショット 2019-07-07 15 47 21 - payjpの画面 スクリーンショット 2019-07-07 15 44 37

前提準備

deviseでのユーザログイン機能の実装

処理の概要

1) pay.jpのgemをインストール

作業目的:Pay.jpを使用できるようにする為

Gemfile
gem 'payjp'

2) Pay.jpの公式のjavascriptを読み込ませられるようする

作業目的:Pay.jpの公式のjavascriptを読み込ませられるようする為

app/views/layouts/application.html.haml

%script{src: "https://js.pay.jp/", type: "text/javascript"}

3) クレジットカードテーブルを作成する

作業目的: クレジットカード情報を保存するテーブルを作成

Colun Type Options 意味
user_id references null: false, foreign_key: true ログインユーザ
costomer_id integer null: false 顧客ID情報(pay.jpから返ってくるデータ)
card_id integer null: false カードID情報(pay.jpから返ってくるデータ)

costomer_id, card_idは、カード情報(16桁のやつ),有効期限年月,セキュリティーコードを渡すとpay.jpから返ってくるデータのこと

db/migrate/***************_create_credit_cards.rb
class CreateCreditCards < ActiveRecord::Migration[5.2]
  def change
    create_table :credit_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

なんで、DBにカード情報とか保存しないの?っと疑問に持たれる人もいると思いますので、ここで解説
以下のURLを参照していただければわかるのですが、
Pay.jp側の方で、
セキュリティーの観点から
クレジット情報は、勝手にDBに保存するな。俺が管理する。お前らにはIDやるから我慢しろ。っと言われているからなんですよねー
めんどいですが、クレジット情報や購入情報は毎回Pay.jpに問い合わせる必要があります。

4) クレジットカード情報の追加と削除のコントローラを作っていきます

1つのget、3つのpostの実装

GET

  • edit

    クレジットカードの新規登録画面
  • confirmation

    クレジットカードを追加するか選択する画面

POST

  • create

    payjpとCardのデータベース作成を実施します。
  • delete

    payjpとCardのデータベースを削除する。
  • show

    DBのCreditCard情報を、payjpに送りcustomer情報を取り出すために実装
app/controllers/credit_cards_controller.rb
class CreditCardController < ApplicationController

  before_action :get_user_params, only: [:edit, :confirmation, :show]
  before_action :get_payjp_info, only: [:new_create, :create, :delete, :show]

  def edit
  end

  def create
    if params['payjp-token'].blank?
      redirect_to action: "edit", id: current_user.id
    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
        redirect_to action: "show"
      else
        redirect_to action: "edit", id: current_user.id
      end
    end
  end

  def delete
    card = current_user.credit_cards.first
    if card.present?
      customer = Payjp::Customer.retrieve(card.customer_id)
      customer.delete
      card.delete
    end
      redirect_to action: "confirmation", id: current_user.id
  end

  def show
    card = current_user.credit_cards.first
    if card.present?
      customer = Payjp::Customer.retrieve(card.customer_id)
      @default_card_information = customer.cards.retrieve(card.card_id)
    else
      redirect_to action: "confirmation", id: current_user.id
    end
  end

  def confirmation
    card = current_user.credit_cards
    redirect_to action: "show" if card.exists?
  end

  private

  def get_payjp_info
    if Rails.env == 'development'
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    else
      Payjp.api_key = Rails.application.credentials.payjp[:PAYJP_PRIVATE_KEY]
    end
  end
end

5) ビュー

作業目的:クレジット情報の、確認と削除、追加のファームを作成する必要があった為。

  • confirmation
app/views/credit_card/confirmation.html.haml
   .main__content
    %section.chapter__container
      %h2.chapter__head 支払い方法
      .payment__main
        .payment__list
          .payment__list__content
            %h3.sub__head クレジットカード一覧
        .add__card
          .payment__list__content
            = link_to edit_credit_card_path(current_user), class: "red__btn", data: {"turbolinks" => false} do
              %i
              = icon('fas', 'credit-card', class: "card__icon")
              クレジットカードを追加する
        .not__regist
          %span 支払い方法について

Image from Gyazo

  • edit
app/views/credit_card/edit.html.haml
   .main__content
    %section.chapter__container
      %h2.chapter__head クレジットカード情報入力
      = form_tag('/credit_card', method: :post, action: "create", id: 'charge-form',  name: "inputForm", class: "chapter__container__inner") do
        .form__main__container
          .form__content
            %label.payment__card カード番号
            %span.require__form 必須
            = text_field_tag "number", "", class: "number input__deafult", placeholder: "半角数字のみ" ,maxlength: "16", type: "text", id: "card_number"
            .card__list
              .card__list__picture
          .form__content.top__margin
            %label.payment__card 有効期限
            %span.require__form 必須
            .select__box.top__margin
              .select__box__half
                %select.select__default#exp_month{name: "exp_month", type: "text"}
                  %option{value: ""} --
                  %option{value: "1"}01
                  %option{value: "2"}02
                  %option{value: "3"}03
                  %option{value: "4"}04
                  %option{value: "5"}05
                  %option{value: "6"}06
                  %option{value: "7"}07
                  %option{value: "8"}08
                  %option{value: "9"}09
                  %option{value: "10"}10
                  %option{value: "11"}11
                  %option{value: "12"}12
                %i
                  = icon('fas', 'chevron-down')
                %span.select__box__half
                .icon
                %select.select__default#exp_year{name: "exp_year", type: "text"}
                  %option{value: ""} --
                  %option{value: "2019"}19
                  %option{value: "2020"}20
                  %option{value: "2021"}21
                  %option{value: "2022"}22
                  %option{value: "2023"}23
                  %option{value: "2024"}24
                  %option{value: "2025"}25
                  %option{value: "2026"}26
                  %option{value: "2027"}27
                  %option{value: "2028"}28
                  %option{value: "2029"}29
                %i
                  = icon('fas', 'chevron-down')
                %span.form__content.top__margin
            %label セキュリティーコード
            %span.require__form 必須
            = text_field_tag "cvc", "", class: "cvc", placeholder: "カード背面4桁もしくは3桁の番号", maxlength: "4", id: "cvc"
            .single__code
              .single__code__text
              %span.form__question ? 
              %span カードの裏面の番号とは?
          #card_token
          = submit_tag "追加する", id: "token_submit", class: "top__margin"

Image from Gyazo

  • show
app/views/credit_card/show.html.haml
   .main__content
    %section.chapter__container
      %h2.chapter__head 支払い方法
      .payment__main
        .payment__list
          .payment__list__content
            %h3.sub__head クレジットカード一覧
        .card__payment__list
          %form.card__payment__content
          .card__list
            .card__list__picture  
          .card__number 
            = "**** **** **** " + @default_card_information.last4
          .expire__date 
            - 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_credit_card_index_path, method: :post, id: 'charge-form',  name: "inputForm") do
            %input{ type: "hidden", name: "card_id", value: "" }
            %button.delete__button 削除する
        .how__not__regist
          %span 支払い方法について

Image from Gyazo

6) トークン作成用のJS

作業目的:payjpにデータを送るために実装。入力されたクレジット情報を参考にし、トークンを作成する

app/assets/javascripts/payjp.js
document.addEventListener(
  "DOMContentLoaded", e => {
    if (document.getElementById("token_submit") != null) { //token_submitというidがnullの場合、下記コードを実行しない
      Payjp.setPublicKey("pk_test_61fe8dd669a59526fd8542f5"); //ここに公開鍵を直書き
      let btn = document.getElementById("token_submit"); //IDが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"); //データを自サーバにpostしないように削除
            $("#card_token").append(
              $('<input type="hidden" name="payjp-token">').val(response.id)
            ); //取得したトークンを送信できる状態にします
            document.inputForm.submit();
            alert("登録が完了しました"); //確認用
          } else {
            alert("カード情報が正しくありません。"); //確認用
          }
        });
      });
    }
  },
  false
);

7) ルーティング

作業目的:最後に、全てのpathを通すためのルーティングを設計します。

config/routes.rb
  resources :credit_card, only: [:create, :show, :edit] do
    collection do
      post 'delete', to: 'credit_card#delete'
      post 'show'
    end
    member do
      get 'confirmation'
    end
  end 

以上で完成です!
とりあえず実装のフローを書いてみました。

感想

商品の購入するためには、クレジット情報が必要になります。
以上の順番で、実装すれば、できるはず!!!

気力があれば、購入のフローも書きたいと思いますー。

25
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?