LoginSignup
19
22

More than 5 years have passed since last update.

RailsでStripe Connectを使ってみる

Posted at

connect.png

インターネットで商売をするのに、決済機能は欠かせません。Stripeは「決済API」で、今回取り扱う「Stripe Connect」はマーケットプレイスに特化した「決済フローAPI」です。

買い手と、売り手がいるマーケットプレイスを構築するためには、買い手によるクレジットカードの決済処理だけでなく、売り手への入金、またそのプラットフォーム(開発者側)による仲介手数料の回収も行なう必要があります。こういう状況に、Stripe Connectは最適です。

Stripe Connectの概念的な説明に関しましては、下記の記事をご参照ください。今回は、Railsで0) Stripeアカウントを作成1) Stripeのセットアップ2) 売り手への入金処理3) 買い手のクレジットカード登録までを実装していく流れを紹介していきます。
https://qiita.com/y_toku/items/7bfa42793801dfc5415d

開発環境

Ruby 2.4.0
Rails 5.2.2
Devise
Stripe Standard

0) Stripeアカウントを作成する

Stripe Connectを開発環境で動かすためには、3つのAPIを取得する必要があります。
0-1) 公開可能キー(publishable_key)を取得します
0-2) シークレットキー(secret_key)を取得します
ダッシュボード > 開発者 > APIキーより取得できます。
api.png

0-3) クライアントID(client_id)を取得します
ダッシュボード > Connect > 設定より取得できます。
connect_api.png

1) Stripeのセットアップ

まず、0)で取得してきたAPIをCredentials Keyに保存します。

credentials.yml
stripe:
  publishable_key: pk_test_************
  secret_key: sk_test_************
  client_id: ca_************

必要なライブラリをbundle installでインストールしていきます。

Gemfile
gem 'stripe'
gem 'omniauth-stripe-connect'

2) 売り手への入金処理を実装する

rails g migration AddStripeAccountToUsers access_code:string publishable_key:stringを実行して、UserモデルにStripeアカウントと紐づけるカラムを追加します。

2019xxxxx_add_stripe_account_to_users.rb
class AddStripeAccountToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :access_code, :string
    add_column :users, :publishable_key, :string
  end
end

続いて、Stripeの設定とコールバックのコントローラーを追加していきます。

devise.rb
・・・
  config.omniauth :stripe_connect,
    Rails.application.credentials[Rails.env.to_sym][:stripe][:client_id],
    Rails.application.credentials[Rails.env.to_sym][:stripe][:secret_key],
    scode: 'read_write',
    stripe_landing: 'login'
・・・
omniauth_callbacks_controller.rb
・・・
def stripe_connect
  auth_data = request.env["omniauth.auth"]
  @user = current_user
  if @user.persisted?
    @user.access_code = auth_data.credentials.token
    @user.publishable_key = auth_data.info.stripe_publishable_key
    @user.save

    sign_in_and_redirect @user, event: :authentication
    flash[:notice] = 'Stripe Account Created And Connected' if is_navigational_format?
   else
     session["devise.stripe_connect_data"] = request.env["omniauth.auth"]
     redirect_to root_path
   end
end
・・・

ViewにStripe Connectボタンを追加します。

edit.html.erb
・・・
   <%= link_to stripe_url do %>
     <%= image_tag ("connect-with-stripe.png") %>
   <% end %>
・・・
application_helper.rb
module ApplicationHelper
  def stripe_url
   "https://connect.stripe.com/oauth/authorize?response_type=code&client_id=#{Rails.application.credentials[Rails.env.to_sym][:stripe][:client_id]}&scope=read_write"
  end    
end

Stripeボタンを押すと、下記のような画面に遷移します。
skip.png

開発モードでは「このアカウントフォームをスキップ」で入金口座の登録などをスキップできます。

最後に、StripeダッシュボードでリダイレクトURLを設定します。
connect_apiのコピー.png

access_codeと、publishable_keyが取得できていれば完了です。

3) 買い手のクレジットカード登録を実装する

クレジットカード情報を自身のアプリケーション上で持たず、フロントから直接Stripeに送るために、JSを使う必要があります。
今回は、RailsアプリケーションとJavaScriptの連携をスムーズに実現してくれるgonというgemを使います。

Gemfile
gem 'gon'

インストールしたgonをViewにセットアップします。

application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Stripe Application</title>
    <%= include_gon %>
    <%= Gon::Base.render_data %>
・・・
application_controller.rb
class ApplicationController < ActionController::Base
    before_action :assign_env_variable

    def after_sign_out_path_for(resource)
      new_user_session_path
    end

    def assign_env_variable
      gon.stripe_key = Rails.application.credentials[Rails.env.to_sym][:stripe][:publishable_key]
    end
・・・

続いて、Stripeのクレジットカード情報と紐づけるトークンを保存しておくカラムを追加します。

2019xxxxx_add_stripe_customer_id_to_users.rb
class AddStripeCustomerIdToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :stripe_customer_id, :string
  end
end

config/initializers配下に、stripe.rbを設定します。

stripe.rb
Rails.configuration.stripe = {
  :publishable_key => Rails.application.credentials[Rails.env.to_sym][:stripe][:publishable_key],
  :secret_key      => Rails.application.credentials[Rails.env.to_sym][:stripe][:secret_key]
}

Stripe.api_key = Rails.configuration.stripe[:secret_key]

UserコントローラーとUserモデルに、下記を追加していきます。

users_controller.rb
class UsersController < ApplicationController

  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      if @user.stripe_temporary_token.present?
        customer = Stripe::Customer.create(
          email: @user.email,
          source: @user.stripe_temporary_token
        )
        @user.update_attribute(:stripe_customer_id, customer.id)
      end
    else
      render :show
    end
    redirect_to @user
  end

  private

  def user_params
    params.require(:user).permit(:email, :stripe_customer_id, :stripe_temporary_token, :provider, :uid, :publishable_key, :access_code)
  end
end
user.rb
class User < ApplicationRecord
・・・
  attr_accessor :stripe_temporary_token
・・・
end

クレジットカードフォームをStripeに送るViewとJS部分を追加します。

edit.html.erb
・・・
<%= form_for(@user, html: {class:'add-card'}) do |f| %>
  <div class="block">
    <%= f.hidden_field :stripe_temporary_token %>
    <div class="formItem">
      <%= f.label :card_number %>
      <div class="formInput"><%= text_field :card_number, placeholder: "Enter card number", data: {stripe: 'number'} %></div>
    </div>
    <div class="formItem">
      <%= f.label :expiration_month %>
      <div class="formInput"><%= select_month(Date.today, {add_month_numbers: true}, id: 'card_month', data: {stripe: 'exp-month'}) %></div>
    </div>
    <div class="formItem">
      <%= f.label :expiration_month %>
      <div class="formInput"><%= select_year(Date.today.year, {start_year: Date.today.year, end_year: Date.today.year + 10}, id: 'card_year', data: {stripe: 'exp-year'}) %></div>
    </div>            
    <div class="formItem">
      <%= f.label :security_code %>
      <div class="formInput"><%= text_field :card_cvc, data: {stripe: 'cvc'}, placeholder: 'CVV/CVC' %></div>
    </div>
  </div>
  <div class="block">
    <div class="button">
      <%= f.submit "Update", id: "submit-card", class: "btn btnSubmit" %>
    </div>
  </div>
<% end %>
・・・
verify_card.js
jQuery(function($) {
  Stripe.setPublishableKey(gon.stripe_key);

  function createCardToken(event) {
  function createCardToken() {
    Stripe.card.createToken(
      {
        number: $("#card_number").val(),
        cvc: $("#card-cvc").val(),
        number: $("#card_number_").val(),
        cvc: $("#card_cvc_").val(),
        exp_month: $("#card_month").val(),
        exp_year: $("#card_year").val()
      },
      stripeResponseHandler
    );
    console.log("token created");
  }

  $("#submit-card").on("click", function(e) {
    createCardToken();
  });

  function stripeResponseHandler(status, response) {
    var $form = $(".add-card");

    if (response.error) {
      // Show the error on the form
      $("#error").text(response.error.message);
      $form.find("input[type=submit]").prop("disabled", false);
    } else {
      // response contains id and card, which contains additional card details
      var token = response.id;
      console.log(token);
      // Insert the token into the form so it gets submitted to the server
      $("input[id=stripe_temporary_token]").val(token);
      // and submit manually
      $form.get(0).submit();
    }
  }

  // If the user doesn't have a stripe customer account & credit card currently tied to their account, this function will execute and intercept the submit event to obtain a stripe token. Once it has it, it will execute the submit action
  $("#card-unavailable").each(function() {
    $(".add-card").submit(function(event) {
      console.log("no card");
      createCardToken();
      // Prevent the form from submitting with the default action, we want the token first.
      return false;
    });
  });
});

これで、stripe_customer_idが取れていれば完了です。

さいごに

実装にあたって、Stripeにお問い合わせをしてみました。担当者の方が親身でかつ、迅速に対応してくれたため、開発の目処をすぐに立てることができました。

まだ日本ではStripe文献は少なく感じましたが、大変便利なのでぜひ使ってみましょう。

参考

Stripe Connect & Rails — Part 1
Stripe Connect & Rails — Part 2

19
22
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
19
22