14
15

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 3 years have passed since last update.

Rails6でStripe Checkoutを実装 (開発環境/TESTモード)

Last updated at Posted at 2021-05-05

背景

Stripe決済を初めて実装する機会があり、参考記事があまりなく苦労したのでまとめてみました。

もし、Rails6でStripe決済を実装することになった駆け出しエンジニアがいたら是非参考にしてもらえると嬉しいです。
また、学習3~4ヶ月目のぺーぺーが書いた記事なので、理解が間違っている、リファクタリングなどあればなんなりと指摘していただけると幸いです。

Stripeには複数の決済手段があるが、今回は一番実装が簡単なCheckoutを実装しました。
ちなみにStripeの公式リファレンスではFWはSinatraなのでご注意ください。

Checkoutとは?: Stripeが用意してくれている決済画面に遷移して決済を行う手段である。

実装内容

  • Stripe Checkout で決済機能を実装
    • 決済完了時にユーザー情報を登録
    • 支払完了後はWEBアプリに戻り、決済完了画面を表示
    • 決済せずにStripe上で「戻る」をしたときに支払キャンセル画面を表示

Stripe側での設定

1. まずはStripeのサイトでアカウント作成

以下のリンクからアカウントを作成しましょう!
[Stripe公式サイト][0]
[0]:https://stripe.com/jp

2. ダッシュボード上の商品タブをクリックし、+ テスト商品を追加をクリック

ダッシュボード(商品).png

3. 商品情報を入力

今回は一括払い、1,000円の商品を作成
商品作成ページ.png

4. 以下の4つのキーを使用

商品ページ内

詳細のID: prod_◯◯◯◯◯◯
料金のAPI ID:price_◯◯◯◯◯◯◯◯◯◯
商品IDと料金ID.png

開発者ページ内APIキーの標準キー

公開可能キー: pk_test_◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯…◯◯◯
シークレットキー: sk_test_◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯…◯◯◯ *第三者に漏洩しないようにご注意ください
公開可能キーとシークレットキー.png

Rails側の手順

■前提

deviseや必要なデータベースは作成済み。
今回、必要なデータベースは以下の感じ。
ユーザーテーブル: name, email, password, customer_id, plan_id + デフォルト
プランテーブル: id, plan_name + デフォルト

もしテーブルの作り方がわからない場合は、簡単にまとめてあるので以下を御覧ください!
参考:[マイグレーションファイルの基本][5]
[5]:https://qiita.com/vit_udon_husqy/items/6142908cca27b2188f0d

実装

少し長いので、コントローラは機能2つに分けて解説します。

■Gemのインストール

Gemfile
gem 'stripe' # Stripeを実装するためのgem
gem 'dotenv-rails' # Stripeの重要な情報を記述するためのgem

bundle installして準備完了

■決済画面への遷移~決済完了ページ or 決済キャンセルページの実装

payments_controller.rb
class PaymentsController < ApplicationController
  
 #決済後の画面遷移
  def new
    @session = Stripe::Checkout::Session.create({
      payment_method_types: ['card'],
      line_items: [{
        price: 'price_XXXXXXXXXXX',  # 料金API-IDを記述
        quantity: 1,
      }],
      mode: 'payment',
      success_url: request.base_url + '/payments/after_payment_register?session_id={CHECKOUT_SESSION_ID}',  # 決済成功後の遷移先
      cancel_url: request.base_url + '/payments/payment_cancel',  #決済キャンセルした際の遷移先
    })   
  end
  
  #決済前のキャンセルのアクション
  def payment_cancel
  end

end

Stripeでは、Railsに実装する際はStripe::Checkout::Session.◯◯◯のような形でセッションオブジェクトを使用してデータを取得します。

参考:[Stripe API reference (Create)][1]
[1]:https://stripe.com/docs/api/checkout/sessions/create
参考:[Stripe Docs][7]
[7]:https://stripe.com/docs/checkout/integration-builder

/payments/new.html.erb
<script src="https://js.stripe.com/v3"></script>

<script>
  var stripe = Stripe('pk_test_XXXXXXXXXXXXXX'); // ()内には公開可能キーを記述
  stripe.redirectToCheckout({
    sessionId: '<%= @session.id %>'
  }).then(function (result) {
  });
</script>

上記ではnewアクションに対するビューの設定です。つまり、決済画面を作っています。
newアクションで作ったインスタンス変数@session(料金、数量等の情報)を決済ページに持っていってくれます。
今回のケースだと payments/new というパスで決済ページにアクセスできます。
スクリーンショット 2021-05-05 22.07.46.png
← 戻るの箇所には元々はショップ名が入ります。
カーソルを持っていくと← 戻るに変わり、クリックするとキャンセル扱いとなり画面遷移します。

ダミーカード番号 4242 4242 4242 4242
その他の情報を適当に入力して「支払う」ボタンを押すと決済完了画面に遷移するはずです!

■決済完了後、データベースにユーザー情報を登録

まず、Stripeの決済は色々な情報を保有しています。欲しいデータが何なのか、事前に整理しておきましょう!

どのようなデータが取れるのかは以下を参考にしてください。
参考:[Stripe API reference][2]
[2]:https://stripe.com/docs/api

今回、ユーザー情報としてStripeから引っ張りたかったのは以下の通り。
-顧客ID(customer_id)
-メールアドレス(email)
-商品ID(product_id)

payments_controller.rb
class PaymentsController < ApplicationController
  
  
  before_action :user_plan_judgement, except: [:new, :payment_cancel]

  INITIAL_USER_NAME = "新規ユーザー"
  STRIPE_PRODUCT_ID = "prod_XXXXXX"  # 商品IDを記述
  
  #(中略)
  
  # 初期パスワードを乱数生成、初期ユーザー名を新規ユーザー、customer_id, email, plan_idをユーザーデータテーブルに登録
  def after_payment_register
    generated_initial_password = Devise.friendly_token.first(8)
    stripe_user_data = Stripe::Checkout::Session.retrieve(params[:session_id])    

    @user = User.new(
      customer_id: stripe_user_data.customer,
      name: INITIAL_USER_NAME,
      email: stripe_user_data.customer_details["email"],
      password: generated_initial_password,
      plan_id: user_plan_judgement
    )
    @user.save
    send_notification_email
  end

  private

  # 1.プランIDを取得
  def user_plan_judgement
    stripe_plan_data = Stripe::Checkout::Session.list_line_items(params[:session_id])
    if stripe_plan_data[:data][0][:price]["product"] == STRIPE_PRODUCT_ID
      plan_id = 1
    end
  end
end

ざっくりですが、以下のことを実行しています。

  1. ユーザーが決済したプランはなにかを判定
  2. 1.を含めたユーザー情報を登録

1. ユーザーが決済したプランはなにかを判定
Stripe::Checkout::Session.list_line_itemsでStripeの商品IDと引っ張ってきたデータのproductデータが一致していれば
plan_idに1を代入するという処理にしました。
現状あまり意味はないのですが、
プランの料金が変わったときでも同一のプランであることとして管理するために設定しました。

参考:[Stripe API reference (line_items)][5]
[5]:https://stripe.com/docs/api/checkout/sessions/line_items

2. 1.を含めたユーザー情報を登録
Devise.friendly_token.first(8)でランダムな8桁のパスワードを設定

Stripe::Checkout::Session.retrieveでレトリーブしてきてくれます。
参考:[Stripe API reference (retrieve)][3]
[3]:https://stripe.com/docs/api/checkout/sessions/retrieve
かわいいレトリーバー犬はこのretrieveから来ているらしいです。
狩った獲物をとってくる(回収してくる)意味らしいです。 (今回のPJの恩師から教えてもらいました。)
参考:[語源由来辞典][4]
[4]:https://gogen-yurai.jp/retriever/
なので、欲しいデータをretrieve(回収)してきてもらうわけです。
retrieveしてもらった獲物(データ)を獲物箱(=変数)へ代入します。

あとは見慣れたUser.newとuser.saveでユーザーデータを保存してユーザー登録も完了!
実際に決済テストを行った後にRails consoleUser.allコマンドで確認すると決済を行ったユーザーが登録されているはずです!

あとは決済後やキャンセル後のページをビューを整えて完成!
ビューで表示する内容はプロジェクトの指定のものか、テンプレート文を調べると良いと思います。

完成形

コントローラ

payments_controller.rb
class PaymentsController < ApplicationController
  before_action :user_plan_judgement, except: [:new, :payment_cancel]

  INITIAL_USER_NAME = "新規ユーザー"
  STRIPE_PRODUCT_ID = "prod_XXXXXX"  # 商品IDを記述
  
  def new
    @session = Stripe::Checkout::Session.create({
      payment_method_types: ['card'],
      line_items: [{
        price: 'price_XXXXXXXXXXX',  # 料金API-IDを記述
        quantity: 1,
      }],
      mode: 'payment',
      success_url: request.base_url + '/payments/after_payment_register?session_id={CHECKOUT_SESSION_ID}',
      cancel_url: request.base_url + '/payments/payment_cancel',
    })   
  end

  def payment_cancel
  end

  def after_payment_register
    generated_initial_password = Devise.friendly_token.first(8)
    stripe_user_data = Stripe::Checkout::Session.retrieve(params[:session_id])    

    @user = User.new(
      customer_id: stripe_user_data.customer,
      name: INITIAL_USER_NAME,
      email: stripe_user_data.customer_details["email"],
      password: generated_initial_password,
      plan_id: user_plan_judgement
    )
    @user.save
    send_notification_email
  end

  private

  def user_plan_judgement
    stripe_plan_data = Stripe::Checkout::Session.list_line_items(params[:session_id])
    if stripe_plan_data[:data][0][:price]["product"] == STRIPE_PRODUCT_ID
      plan_id = 1
    end
  end
end

ビュー

/payments/new.html.erb
<script src="https://js.stripe.com/v3"></script>

<script>
  var stripe = Stripe('pk_test_XXXXXXXXXXXXXX'); // ()内には公開可能キーを記述
  stripe.redirectToCheckout({
    sessionId: '<%= @session.id %>'
  }).then(function (result) {
  });
</script>
after_payment_register.html.erb
 <p>決済してユーザー登録したぞ</p>
  <p>決済後に表示されるページだよ</p>
  <p>必要に応じてhtmlで文章記述</p>
payment_cancel.html.erb
  <p>キャンセルされたときに表示されるページだよ</p>

その他(ルーティング、env)

routes.rb
(中略)

resources :payments, only: [:new]
  get '/payments/after_payment_register', controller: 'payments', action: 'after_payment_register'
  get '/payments/payment_cancel', controller: 'payments', action: 'payment_cancel'

(中略)

.env
*ここはGithubにpushされないファイルなので、隠したい定数はここに書きます。

//以下はシークレットキー
STRIPE_TEST_SECRET_KEY = sk_test_XXXXXXXXXXXXXXXXXX

終わりに

長くなりましたが、ご覧いただきありがとうございました!
今回、初めてStripe決済を実装する機会をいただくことができ、自分で実装した中で理解したことをまとめてみました。
Stripe::Checkout::Session.◯◯◯で自在にデータを取得できるのは本当に便利だなあと実感しました。
また、MVC、データの取得~保存、データベースの構築まで自分でやれたのでデータ関連の理解が深まったと感じます。

次回は本番環境の実装についてまとめられたらまとめてみようと思います。

14
15
3

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
14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?