近年、サブスクのサービスが増えましたね。
今回はユーザーの上位プランをサブスクで決済できるようにしたいと思います。
プレミアム会員を月額100円で実装してみます!
下準備
Gemをインストールします。
Gemfile
gem "stripe"
Stripeのアカウントを作成します。
開発環境で動作確認するだけであれば、アカウントを作成するだけですぐに使えます!
環境変数を追加します。
https://dashboard.stripe.com/test/apikeys からAPIキーを持ってきます。
credentials
に保存しましょう。
$ rails credentials:edit -e development
エディタが開いたら以下を参考にAPIキーを設定します。
stripe: publishable_key: pk_test_~~~~ secret_key: sk_test_~~~~
次に、 config/initializers/stripe.rb
を作成し、以下の内容で保存します。
Stripe.api_key = Rails.application.credentials.dig(:stripe, :secret_key) Stripe.api_version = '2024-06-20'
※ APIのバージョン情報は こちら で確認できます。
ユーザー認証を作っておきましょう。
こちらの記事などを参考に、ユーザー認証を準備します。
deviseを使ったものでも大丈夫です。
usersテーブルにカラムを足します。
$ bundle exec rails g migration stripe_to_users
db/20240910000000_stripe_to_users.rb
class StripeToUsers < ActiveRecord::Migration[7.1] def change add_column :users, :premium, :boolean, default: false add_column :users, :customer_id, :string end end
※ customer_id
はStripeの顧客IDを保存するために使用します。
Paymentモデルを追加します。
$ bundle exec rails g model payment
db/20240910000000_create_payments.rb
class CreatePayments < ActiveRecord::Migration[7.1] def change create_table :payments do |t| t.references :user t.string :price_id t.string :subscription_id t.string :product_id t.string :customer_id t.integer :price t.timestamps end end end
※ Stripeで決済した情報を保存するために使用します。必要に応じて、カラムを足しましょう。
決済を実装する
料金を作成する
こちら で料金を作成します。
料金の作成から全てRailsで実装することもできますが、今回は月額100円の料金プランだけなので手動で作成します。
「+商品を追加」ボタンを押し、以下の画像のように入力して登録します。
一覧に「プレミアムプラン」が作成されたかと思います。
プレミアムプランを選択すると「料金」という項目が表示されます。
先ほど作成した「¥100」を選択します。
画面右上にある 「price_~~~」は後で使用するのでコピーしておきましょう。
プレミアムプランへの動線を作る
ルーティングを追加します。
config/routes.rb
resources :plans, only: [:index]
コントローラーを作成します。
app/controllers/plans_controller.rb
class PlansController < ApplicationController def index; end end
viewsを作成します。
app/viewa/plans/index.html.erb
<%= button_to checkouts_path, data: { turbo: false } do %> プレミアムプラン(¥100/月)に申し込む <% end %>
Stripeで決済する
ルーティングを追加します。
config/routes.rb
resources :checkouts, only: [:create]
コントローラーを作成します。
app/controllers/checkouts_controller.rb
class CheckoutsController < ApplicationController def create create_customer if current_user.customer_id.blank? price_id = 'price_~~~' #先ほどコピーした値 session = Stripe::Checkout::Session.create( customer: current_user.customer_id, mode: "subscription", payment_method_types: ["card"], line_items: [ { quantity: 1, price: price_id } ], success_url: root_url, cancel_url: plans_url ) redirect_to session.url, allow_other_host: true end private def create_customer customer = Stripe::Customer.create({ name: current_user.name, email: current_user.email, }) current_user.update(customer_id: customer.id) end end
ここまでで決済ができるようになっています。
実際に「プレミアムプラン(¥100/月)に申し込む」ボタンを押してみると、Stripeのカード情報入力ページへ遷移すると思います。
ここで使用できるテストカードは こちら を参考にしてください。
Webhookを使用できるようにする
Stripe CLIをインストールします。
ローカル環境でWebhookを使用するためにStripe CLIをインストールします。
$ brew install stripe/stripe-cli/stripe
CLIにログインします。
$ stripe login
ローカル環境にイベントを送信します。
stripe listen --forward-to localhost:3000/webhooks
「Your webhook signing secret is whsec_~~」 と表示されるかと思います。
ここに表示されている、 whsec_~~~
はWebhook用のsecretなのでコピーしましょう。
環境変数を追記します。
$ rails credentials:edit -e development
エディタが開いたら以下を参考にWebhook用のsecretを設定します。
stripe: publishable_key: pk_test_~~~~ secret_key: sk_test_~~~~ endpoint_secret: whsec_~~~~
Stripeで決済した情報を保存する
Stripeで決済した情報を保存できるようにWebhookを実装します。
ルーティングを追加します。
config/routes.rb
resources :webhooks, only: [:create]
コントローラーを作成します。
app/controllers/webhooks_controller.rb
class WebhooksController < ApplicationController skip_before_action :verify_authenticity_token skip_before_action :signed_in_user def create payload = request.body.read sig_header = request.env['HTTP_STRIPE_SIGNATURE'] endpoint_secret = Rails.application.credentials.dig(:stripe, :endpoint_secret) event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, endpoint_secret ) rescue JSON::ParserError => e # Invalid payload p e status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature p e status 400 return end case event.type when 'checkout.session.completed' session = event.data.object user = User.find_by(customer_id: session.customer) return unless user ApplicationRecord.transaction do line_item = Stripe::Checkout::Session.list_line_items(session.id).data.first Payment.create!( user_id: user.id, subscription_id: session.subscription, product_id: line_item.price.product, price_id: line_item.price.id, customer_id: session.customer, price: line_item.price.unit_amount, ) user.update!(premium: true) rescue => e p e end end end end
今回は checkout.session.completed
のイベントをトリガーして決済した情報を保存しました。
他にも invoice.payment_succeeded
などがあり、領収書(PDF)のURLを取得することができます。
イベントごとにデータを保存することができるので、痒いところに手が届く感じがしますね!
決済情報を保存したあとは、ユーザーがプレミアム会員になった旨を保存して完成です。
終わり
これでサブスク決済ができるようになりました。
複数のプランがある場合や、プレミアム会員だけ特定の機能が使えるようにするなどの実装は本記事では割愛します。
pr_~~
や price_~~
、 sub_~~~
などStripe独自のIDは種類が多いので最初はこんがらがってしまうかもしれません。
また、サブスク決済の日本語記事が少ない&少々古かったため、APIが動かなくて苦戦してしまいました。