-
Notifications
You must be signed in to change notification settings - Fork 154
Subscriptions
-
Add Payola to your Gemfile:
gem 'payola-payments'
-
Run the installer and install the migrations:
$ rails g payola:install $ rake db:migrate
-
Configure Payola for your needs. You can find out more in https://github.com/peterkeen/payola/wiki/Configuration-options.
-
Add the models
Payola has it's own
Payola::Subscription
model used for tracking subscriptions, but you'll need to create one to represent your plans. We'll create aSubscriptionPlan
model here:$ rails g model SubscriptionPlan \ amount:integer \ interval:string \ stripe_id:string \ name:string
Make sure you include
Payola::Plan
:class SubscriptionPlan < ActiveRecord::Base include Payola::Plan end
A plan model requires a few attributes and has some more optional ones:
-
amount:integer
, (attribute) an amount in the format that Stripe expects. For USD this is cents. -
interval:string
, (attribute) one of'day'
,'week'
,'month'
, or'year'
-
stripe_id:string
, (attribute) a unique identifier used at Stripe to identify this plan -
name:string
, (attribute) a name describing this plan that will appear on customer invoices -
interval_count:integer
, (attribute) optional the number of intervals between each subscription -
trial_period_days:integer
, (attribute) optional the number of days for the trial period on this plan
-
You can of course also add your own attributes to use in relation to the plan.
IMPORTANT NOTE: creating a new plan will queue a background job to create it on Stripe if it does not exists.
Currently we only support custom forms and the checkout button. Here's an example of a custom subscription form that you can drop right into app/views/subscriptions/new.html.erb
:
<!-- this header can go in <head> or at the bottom of <body> -->
<%= render 'payola/transactions/stripe_header' %>
<%= form_tag('/subscriptions',
class: 'payola-onestep-subscription-form',
'data-payola-base-path' => '/payola',
'data-payola-plan-type' => @plan.plan_class,
'data-payola-plan-id' => @plan.id
) do |f| %>
<span class="payola-payment-error"></span>
Email:<br>
<input type="email" name="stripeEmail" data-payola="email"></input><br>
Card Number<br>
<input type="text" data-stripe="number"></input><br>
Exp Month<br>
<input type="text" data-stripe="exp_month"></input><br>
Exp Year<br>
<input type="text" data-stripe="exp_year"></input><br>
CVC<br>
<input type="text" data-stripe="cvc"></input><br>
<input type="submit"></input>
<% end %>
Payola's subscription behavior is triggered by the class payola-onestep-subscription-form
on the form and configured with data
attributes. There are currently three data attributes that all must be present:
-
payola-base-path
is the path where you've mounted Payola in your routes, which is usually/payola
. -
payola-plan-type
is the value returned byplan_type
on the object that includesPayola::Plan
. -
payola-plan-id
is the value returned byid
on the object that includesPayola::Plan
.
When the customer fills out this form and hits the submit button, Payola will:
- Contact Stripe to get a token from the credit card information
- POST your form asynchronously (see below for an example controller)
- Creates the Stripe::Subscription record asynchronously
- On the client, waits for subscription processing to finish before redirecting to the URL specified by
SubscriptionPlan#redirect_path
. Here's what that should look like:
class SubscriptionPlan < ActiveRecord::Base
include Payola::Plan
def redirect_path(subscription)
# you can return any path here, possibly referencing the given subscription
'/'
end
end
Here's what your subscriptions controller should look like:
class SubscriptionsController < ApplicationController
# bring in the `render_payola_status` helper.
include Payola::StatusBehavior
def new
@plan = SubscriptionPlan.first
end
def create
# do any required setup here, including finding or creating the owner object
owner = current_user # this is just an example for Devise
# set your plan in the params hash
params[:plan] = SubscriptionPlan.find_by(id: params[:plan_id])
# call Payola::CreateSubscription
subscription = Payola::CreateSubscription.call(params, owner)
# Render the status json that Payola's javascript expects
render_payola_status(subscription)
end
end
Make sure to add it to your config/routes.rb
as well:
resources :subscriptions
You can add a relation between the owner and the subscription.
class User < ApplicationRecord
has_one :subscription, ->(sub) { where.not(stripe_id: nil) }, class_name: "Payola::Subscription", foreign_key: :owner_id
end
To subscribe using the checkout button, use the checkout
partial like this:
<%= render 'payola/subscriptions/checkout', plan: YourSubscriptionPlanClass.first %>
This will insert a Stripe Checkout button.
Important note: When you use the checkout button with subscriptions payola does not use the controller setup we talked about above. Instead, it will redirect to the plan's redirect_url
. You can attach an owner by setting an event subscriber for payola.subscription.active
:
Payola.configure do |config|
config.subscribe('payola.subscription.active') do |sub|
user = User.find_by(email: sub.email)
if user.nil?
raw_token, enc_token = Devise.token_generator.generate(
User, :reset_password_token)
password = SecureRandom.hex(32)
user = User.create!(
email: sub.email,
password: password,
password_confirmation: password,
reset_password_token: enc_token,
reset_password_sent_at: Time.now
)
WhateverYourPasswordMailerIsNamed.whatever_the_mail_method_is(user, raw_token).deliver
end
sub.owner = user
sub.save!
end
end
The checkout
partial has a bunch of options:
-
plan
: The plan to subscribe to. Required. -
button_text
: What to put on the button. Defaults to "Subscribe Now" -
button_class
: What class to put on the actual button. Defaults to "stripe-button-el". -
quantity
: The quantity of this subscription. Defaults to 1. (see this and this) -
name
: What to put at the top of the Checkout popup. Defaults toplan.name
. -
description
: What to show as the description in the popup. Defaults to plan name + ((the formatted price * quantity) per month). -
plan_image_path
: An image to insert into the Checkout popup. Defaults to blank. -
panel_label
: The label of the button in the Checkout popup. -
allow_remember_me
: Whether to show the Remember me checkbox. Defaults to false. -
email
: Email address to pre-fill. Defaults to blank. -
custom_fields
: Data to pass to thecharge_verifier
(see Configuration Options)
IMPORTANT NOTE: By default, for Canceling/Upgrading/Downgrading/Subscription quantity updates, Payola does not check to verify that the current user actually has permission to cancel the given subscription. To add that, implement a method in your ApplicationController
named payola_can_modify_subscription?
, which takes the subscription in question and returns true or false. For Devise this should look something like:
def payola_can_modify_subscription?(subscription)
subscription.owner == current_user
end
You can add a button to cancel a subscription like this:
<%= render 'payola/subscriptions/cancel', subscription: @subscription %>
The cancel
partial has the following options:
-
button_class
: The CSS class to give the button. -
button_text
: What to put on the button. Defaults to "Cancel Subscription" -
button_id
: the ID to assign to the button -
confirm_text
: the test for the JS alert. Defaults to "Are you sure?" -
url
: the path to submit cancelation to. Defaults to "payola.cancel_subscription_path(subscription.guid)" -
at_period_end
: if true, cancel subscription at end of billing period. Defaults to "false" (immediate)
You can upgrade and downgrade subscriptions by POSTing to payola.change_subscription_plan_path(subscription)
and passing plan_class
and plan_id
for the new plan as params. You can also pass an optional quantity
parameter if you require it. Payola provides a partial for you:
<%= render 'payola/subscriptions/change_plan',
subscription: @subscription,
new_plan: @new_plan,
quantity: 1 %>
You can pass a coupon code to Payola by adding a data-payola="coupon"
input to your form. The coupon code will be passed directly to Stripe and attached to the subscription.
Currently, a quantity of 1 is passed to Stripe upon creation of a Subscription. If you'd like to pass a different quantity (see this and this for reasons why you might want to do this), add a data-payola="quantity"
input to your form. The quantity will be passed directly to Stripe and attached to the subscription.
Also, if you'd like to update the quantity of the subscription later (e.g. customer adds users to their account, and you charge $/user/month), you can POST
a form to payola.change_subscription_quantity_path(subscription.guid)
with a quantity parameter, or you can simply call Payola::ChangeSubscriptionQuantity.call(subscription, quantity)
, where subscription
is a Payola::Subscription
and quantity
is an integer
. The latter will bypass Payola's payola_can_modify_subscription?
method, so check for permissions before calling the change directly.