#概要
僕がサブスクリプション決済を導入する際に参考にしたこちらの記事をもう少し詳しくしたような記事です。
https://qiita.com/tady/items/7617e62b2a5402ebd0fb
#事前準備
deviseというgemを使ったりして、Userモデルは作成しておいてください。僕はRails turorial第6版の完成品を使いました。
#注意
・この記事で扱うプランは一つです。複数のプランに関しては取り扱っておりません。
・無料プランすら扱っていません
#では始めましょう
まずこちらでstripeのアカウント登録を済ませてください。
https://dashboard.stripe.com/register
次にこちらでapi_keyをコピーできるようにしておいてください。
https://dashboard.stripe.com/account/apikeys
Railsアプリで
EDITOR="vi" rails credentials:edit
(local環境の場合はrails→bin/railsと打ち込む)
と打ち込み、
app/config/credentials.yml.encを開いてください
形式はvimなので、基本的なvimの使い方は各自お調べください。(iを押すと入力できるようになりEscを押して:wqと入力すると保存ができます。移動は基本的にキーボードの矢印キーを使います。)
stripe_publishable_key: pk_test_xxxxxxxxxxxxxxx
stripe_api_key: sk_test_xxxxxxxxxxxxx
としてください。各々のキーは
Rails.application.credentials.stripe_publishable_key
Rails.application.credentials.stripe_api_key
で取り出せます。
次にRailsアプリとStripeを繋げるためにapp/config/initializers/stripe.rb
というファイルを作成してください。
Stripe.api_key = Rails.application.credentials.stripe_api_key
これで接続が完了しました。
次にhttps://dashboard.stripe.com/test/products
で商品と料金(プラン)を設定してください。
プランの種類が100種類とかでない限り、Railsからプランをつくるのはお勧めしません。公式ページで手動で作りましょう。
商品をクリックし、料金の欄を見ると作成したプランのAPI_IDが見つかるはずです。(price_xxxxってやつ)
どっかにメモしておいてください。あとで使います。
次はgemのインストールです。
gem 'stripe'
つづいて
bundle install
サーバーを起動している場合は再起動を忘れないようにしてください。
#ここからが大変です
ここから難易度があがるのでわかりにくくなったら
こちらの記事の図を見てくださいね
https://qiita.com/tady/items/7617e62b2a5402ebd0fb
どのユーザーがどのサブスクIDとつながっているかを確認するTeamモデルを作成します。
rails g model team user:references customer_id:string active_until:datetime stripe_subscription_id:string plan_id:string
(注意)customer_id, stripe_subscription_id, plan_idはstring型です。integer型ではありません。active_untilは次の決済日を表しています。 user:referenceは黒魔術のようなものなので気にしなくてOKです。どうしても気になる方は各自お調べください。team.rbは以下のもので上書きしてください。
class Team < ApplicationRecord
belongs_to :user
validates_uniqueness_of :plan_id, scope: :user_id
with_options presence: true do
validates :user_id
validates :customer_id
validates :active_until
validates :stripe_subscription_id
validates :plan_id
end
end
validates_uniqueness_of :plan_id, scope: :user_id
ではユーザー1人につき、1つしかSubscriptionを契約できないようにしています。つまり、二重決済が発生しないようにしています。
with_options presence: true do
のブロックでは、四つのカラムすべてにバリデーションを書けています。(presence :true)
validates :user_id, presence: trueなどのバリデーションを書けてもいいのですが、まとめてかけたほうが早いため上記のようにしております。
(customer_idやstripe_subscription_idがあるからcustomerモデルとかstripe_subscriptionモデルとか必要なのかなと考えるかたがいらっしゃるのはわかりますが、使わないのでモデルは作らないが吉です。)
ルートを追加します
Rails.application.routes.draw do
resources :teams, only: [:new, :create, :destroy]
end
コントローラーを作成します。
rails g controller teams
ビューを新しく作成します
<%= form_tag teams_path do %>
<article>
<% if flash[:error].present? %>
<div id="error_explanation">
<p><%= flash[:error] %></p>
</div>
<% end %>
<label class="amount">
<span>料金: 500円</span>
</label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key = "pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
data-description="A month's subscription"
data-amount="500"
data-locale="ja"
data-currency="JPY"
data-label="購入する">
</script>
<% end %>
<%= link_to "解約する",@team, method: :delete, data: { confirm: "解約しますがいいですか?"}%>
いろいろ突っ込みどころはあるでしょうがひとまず置いときましょう。後で解説します。ちなみにこの記事では契約も解約もこのnew.html.erbで完結させます。
#コントローラを作成
重要な部分なので強調しておきました。
コントローラは以下をコピペしてください。
class TeamsController < ApplicationController
def new
@user = current_user
@team = Team.find_by(user_id: @user.id)
end
def create
@team = Team.new(user_id: current_user.id)
customer = Stripe::Customer.create({
source: params[:stripeToken]
})
subscription = Stripe::Subscription.create({
customer: customer.id,
plan: "price_xxxxxxxxxxxxxxxxxxxxxxx"
})
@team.plan_id = "price_xxxxxxxxxxxxxxxxxxxxxxx"
@team.customer_id = customer.id
@team.stripe_subscription_id = subscription.id
@team.active_until = Time.zone.at(subscription.current_period_end)
if @team.save
flash[:success] = "成功しました"
redirect_to root_url
else
render 'new'
end
end
def destroy
@team = Team.find_by(user_id: current_user.id)
deleting_stripe_subscription = Stripe::Subscription.retrieve(@team.stripe_subscription_id)
if current_user.unsubscribe
deleting_stripe_subscription.delete
flash[:notice] = "解約に成功しました"
redirect_to root_url
else
render 'new'
end
end
end
二回目で申し訳ないですがCustomerモデルとかSubscriptionモデルとか作成する必要はありません。Stripeが勝手に全部やってくれます(なんて便利なんだ!)
ちょっとわかりにくいStripe::Subscription.retrieve(@team.stripe_subscription_id)
の説明だけしておくと、retrieveはStripe側のモデルにおけるfindだと思えば十分です。
current_user.unsubscribe
はUser.rbを見ればわかります。
User.find(1)
とするとidが1のユーザーが見つかるように、
Stripe::Subscription.retrieve(@team.stripe_subscription_id)
とすれば
IDが合致するサブスクリプション契約をStripe側が勝手に見つけてくれます。
続いてuser.rbに行きましょう
class User < ApplicationRecord
has_one :team
def unsubscribe
team = Team.find_by(user_id: self.id)
team.destroy
end
end
これでコントローラが何をしていたかわかりましたね!!
#Viewの解説
さっき飛ばしたViewの説明をします。
<%= form_tag teams_path do %>
<article>
<% if flash[:error].present? %>
<div id="error_explanation">
<p><%= flash[:error] %></p>
</div>
<% end %>
<label class="amount">
<span>料金: 500円</span>
</label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key = "pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
data-description="A month's subscription"
data-amount="500"
data-locale="ja"
data-currency="JPY"
data-label="購入する">
</script>
<% end %>
<%= link_to "解約する",@team, method: :delete, data: { confirm: "解約しますがいいですか?"}%>
<% if @team %>
<p>次回の決済日は<%= @team.active_untilstrftime("%Y年%m月%d日 %H:%M:%S").to_s %>です。</p>
<p>登録日が月末付近の場合ご注意ください</p>
<% end %>
(注意!、<%= @team.active_until %>はなにも設定しないと、グリニッジ標準時間が表示されます。日本時間にしたい場合は"Rails 日本時間"でググるとすぐ出てきます。)
はstripe側が用意してくれたformでこれだけで決済が完結します。
data-keyには公開可能keyを直接入れるとうまくいきます。(グローバル変数にpublish_keyを格納して、scriptタグに突っ込んでもうまくいかず、公開可能鍵だからむき出しでいいか。と、ほったらかしにしている状態です。どなたか解決方法をご享受いただければ幸いです。)
実際に/teams/newにいきボタンを押して
・自分のメアド
・test用VISAカードの番号(4242424242424242)
・有効期限(未来ならいつでも。12/99とか)
・セキュリティコード(好きな3桁の数字)
を入力してみましょう。root_urlにちゃんとredirectされるはずです(root_urlのredirect先のページを作成するのも忘れないでくださいね。)。
stripeのダッシュボードから商品→プランへといってみましょう。反映されているはずです。
consoleからの確認もできます。rails console
で
team = Team.first
team.stripe_subscription_id
>sub_xxxxxxxx
となっていれば成功です。(stripe_subscription_idはstring型になっていますね///)
解約もしてみましょう。こちらもうまくいくはずです。
再び、rails console
で
team = Team.first
>nil
となれば成功です。
#before_acctionを追加
#(current_userがある前提)
def subscribed?
if current_user.nil?
return false
else
team = Team.find_by(user_id: current_user.id)
!team.nil?
end
end
class ApplicationController < ActionController::Base
include SessionsHelper
def subscribed_user
unless subscribed?
flash[:danger] = "Please subscribe"
redirect_to new_team_path
end
end
end
これでいろいろなコントローラで
before_action :subscribed_user, only: [:new, :create, :edit, :update, :destroy]
とすることでお金を払っていないユーザーさんの利用を制限できるようになりました。
#Special Thanks
https://qiita.com/tady/items/7617e62b2a5402ebd0fb
こちらの記事の筆者である@tadyさん。
本当に助かりました!!
#あとがき
ここまで読んでいただき、ありがとうございました。日本の経済が発展することを願って。