Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@tokiya_takai

Payjp v2をRuby on Railsアプリに導入する:カード登録処理編

作成中のポートフォリオにクレジットカード決済を導入しようとして、payjp.js v1公式リファレンスを除きにいくと、こんな文言が。

将来的にこちらは非推奨(deprecated)となる予定です。最新のPCI-DSSに準拠したpayjp.js v2をご利用ください。

ということで、最新のPCI-DSSに準拠できるようにv2を導入することにしました。

PCIDSSとは|日本カード情報セキュリティ協議会 - JCDSC

payjp.js v2リファレンスはこちらをご確認ください。
payjp.js v2 リファレンス

前提条件

・deviseによるユーザー管理機能を実装している
・商品がある(テーブルが作成されている)
・payjpに登録し、テスト用の公開鍵と秘密鍵を取得できる
・payjpのgemをインストールしている(していない場合は下記を実行してください。)

Gemfile
gem 'payjp'
ターミナル
% bundle install

※なお、本記事でのターミナルの操作は、すべて当該アプリケーションディレクトリ内で行います。

まずは処理の流れを確認(コントローラ名#アクション名)

  1. カード登録処理 ←今回はこっちやで
    1. カード登録画面へ遷移(cards#new)
    2. カードを登録(cards#pay)
    3. カード情報表示ページへ遷移(cards#show)
    4. (必要であれば)カード情報を削除(cards#delete)
  2. 購入処理 次回
    1. 購入画面へ遷移(orders#new)
    2. 購入ボタンを押下→確認画面へ遷移(orders#confirm)
    3. 購入確定ボタンを押下(orders#create)
    4. 購入完了画面へ遷移(orders#complete)

それでは実装していきましょう

カード登録処理

カード登録画面へ遷移

まずは、payjpを使えるようにしていきます。

application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Moroheiya</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <script src="https://js.pay.jp/v2/pay.js"></script>
    #この1行を追加

  #省略

スクリプトの内容は、公式リファレンスに記述してあります。
payjp.js v2 リファレンス

・ルーティングを設定していきます。
config/routes.rb
resources :cards, only: [:new, :show] do
 collection do
   post 'show', to: 'cards#show'
   post 'pay', to: 'cards#pay'
   post 'delete', to: 'cards#delete'
 end
end

これで今回使う処理のルーティングはすべてです。

・次にcardsテーブルを作っていきます。

モデルを作成します。

% rails g model card

アソシエーションを組みます。

card.rb
class Card < ApplicationRecord
  belongs_to :user
end
user.rb
class User < ApplicationRecord
  #省略
  has_one :card
  #省略
end

マイグレーションファイルを記述します。

db/migrate/xxxxxxxxxxxxxx_create_cards.rb
class CreateCards < ActiveRecord::Migration[6.0]
  def change
    create_table :cards do |t|
      t.references :user, foreign_key: true
      t.string :customer_id
      t.string :card_id
      t.timestamps
    end
  end
end

記述したら、マイグレートします。

% rails db:migrate
・コントローラを作成します。
% rails g controller cards

cards_controllerを作成できたら、コントローラに記述していきます。
下記のように記述してください。

cards_controller.rb
class CardsController < ApplicationController

  require 'payjp' #payjpのメソッドを使用できるようにします。

  def new
    card = Card.where(user_id: current_user.id)
  end
end

記述したら、ビューを作成していきます。

views/cards/new.html.erb
<p id="number-form" class="payjs-outer></p>
<p id="expiry-form" class="payjs-outer"></p>
<p id="cvc-form" class="payjs-outer></p>

<%= form_with url: pay_cards_path, method: :post, id: "card_form" do |f| %>
  <div id="card_token"></div>
  <%= f.submit "登録する", class:"btn", id: "info_submit" %>
<% end %>

必要なものだけピックアップしました。見栄えは悪いので、適宜HTMLを記述して整えてください。

そして、登録するボタンを押した際に発火するJavaScriptを作成します。

payjp.js
$(function () {
  //URLにcardsが含まれている際に発火します。
  if (document.URL.match(/cards/)){

    //公開鍵を記述
    var payjp = Payjp('pk_test_xxxxxxxxxxxxxxxxxxxxxxxx');
    //Elements インスタンスを生成します。
    var elements = payjp.elements();
    var numberElement = elements.create('cardNumber');
    var expiryElement = elements.create('cardExpiry');
    var cvcElement = elements.create('cardCvc');

    numberElement.mount('#number-form');
    expiryElement.mount('#expiry-form');
    cvcElement.mount('#cvc-form');

    var submit_btn = $("#info_submit");
    submit_btn.on('click', function (e) {
      e.preventDefault();
      payjp.createToken(numberElement).then(function (response) {

        if (response.error) {  //  通信に失敗したとき
          alert(response.error.message)
          regist_card.prop('disabled', false)
        } else {
          $("#card_token").append(
            `<input type="hidden" name="payjp_token" value=${response.id}>
            <input type="hidden" name="card_token" value=${response.card.id}>`
          );
          $('#card_form')[0].submit();

          $("#card_number").removeAttr("name");
          $("#cvc-from").removeAttr("name");
          $("#exp_month").removeAttr("name");
          $("#exp_year").removeAttr("name");
        };
      });
    }); 
  }
});

参考ページ:payjp.js v2 リファレンス
これで、カード登録ページに遷移するところまで実装できました。

カードを登録

・鍵の設定

カードの登録には、payjpで登録したアカウントの公開鍵と秘密鍵が必要です。
payjp_api.png

画像引用:Railsで Payjp.js V2 でクレジットカード登録機能実装 フリマアプリ

現状ではテスト鍵を使用してください。

これらを.envファイルに保存して、環境変数として扱えるようにします。
今回は、dotenvを使用します。

Gemfile
gem 'dotenv-rails'
% bundle install

インストールできたら、.envファイルを作成します。

% touch .env

ルートディレクトリ内に.envファイルが生成されていると思うので、記述していきます。

PAYJP_PUBLIC_KEY='pk_test_xxxxxxxxxxxxxxxxxxxxxxx'
PAYJP_SECRET_KEY='sk_test_xxxxxxxxxxxxxxxxxxxxxxxx'

パブリックキー(公開鍵)と、シークレットキー(秘密鍵)を間違えないよう注意してください。

このファイルは間違ってGitにあげてしまわないように、.gitignoreに記述しておきます。

.gitignore
.env

これで鍵の設定は終わりました。

・登録処理

コントローラに以下を記述してください。

cards_controller.rb
#newアクションの下で大丈夫です。

def pay
  Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
  if params['payjp_token'].blank?
    redirect_to action: "new"
  else
    customer = Payjp::Customer.create(
    description: '登録テスト',
    email: current_user.email,
    card: params['payjp_token'],
    metadata: {user_id: current_user.id}
    )
    @card = Card.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: "pay"
    end
  end
end

さらに、showアクションの追加と、newアクションへ追記を行います。

cards_controller.rb

def new
  card = Card.where(user_id: current_user.id)
  redirect_to action: "show" if card.exists?
end

#省略

def show
  card = Card.find_by(user_id: current_user.id)
  if card.blank?
    redirect_to action: "new" 
  else
    Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
    customer = Payjp::Customer.retrieve(card.customer_id)
    @default_card_information = customer.cards.retrieve(card.card_id)
  end
end

これで、カード登録画面へ遷移した時にカードが存在していればカード情報表示ページへ遷移、無ければ登録画面へ遷移する処理と、カードを作成し終えたらカード情報表示ページへ遷移する処理になりました。

カード情報表示ページのビューを作成します。同時に削除ボタンも作成しておきましょう。

cards/show.html.erb
<%= "**** **** **** " + @default_card_information.last4 %>
<br />
<% 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_with url:delete_cards_path, method: :post, id: 'charge-form', name: "inputForm", local: true do %>
  <input type="hidden" name="card_id" value="">
  <button>削除する</button>
<% end %>

カード情報削除処理

購入機能に必須ではないですが、一応実装しておきましょう。

cards_controller.rb

#省略

def delete
  card = Card.find_by(user_id: current_user.id)
  if card.blank?
  else
    Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
    customer = Payjp::Customer.retrieve(card.customer_id)
    customer.delete
    card.delete
  end
  redirect_to action: "new"
end

#省略

以上でカードの登録処理は完了です。

参考記事

コードなどは他者さんのをほぼ使っていたりするのですみません。
Railsで Payjp.js V2 でクレジットカード登録機能実装 フリマアプリ

Payjpでクレジットカード登録と削除機能を実装する(Rails)

2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
tokiya_takai
1つのアプリを作るためのコードではなく、必要なところだけを抜粋し、ご覧いただいた皆さんのアプリケーションにも取り入れやすいような記事にするよう心がけています。Ruby on Rails、JavaScript、HTML、CSS、C言語がある程度書けます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?