Skip to content

Instantly share code, notes, and snippets.

@rpheath
Created March 22, 2011 05:39
Show Gist options
  • Save rpheath/880830 to your computer and use it in GitHub Desktop.
Save rpheath/880830 to your computer and use it in GitHub Desktop.
development:
subdomain: development-subdomain
api_key: XXX
site_key: XXX
production:
subdomain: production-subdomain
api_key: XXX
site_key: XXX
require 'chargify_api_ares'
begin
# loads in the data from the YAML file in the config directory
chargify_config = YAML::load_file(File.join(Rails.root, 'config', 'chargify.yml'))
# configure Chargify for the existing Rails environment
Chargify.configure do |c|
c.subdomain = chargify_config[Rails.env]['subdomain']
c.api_key = chargify_config[Rails.env]['api_key']
end
rescue
nil
end
class PaymentProcessor
# used for the initial signup flow
def self.hosted_signup_page_for(plan, user)
"https://#{self.subdomain}.chargify.com/h/#{self.product_id(plan)}/subscriptions/new?first_name=#{user.first_name}&last_name=#{user.last_name}&email=#{user.email}&reference=#{user.token}"
end
# used to send a user to their unique payment page in
# the event that they need to update their payment details
def self.update_payment_url_for(account)
return nil if (subscriber_id = account.chargify_subscriber_id).blank?
"https://#{self.subdomain}.chargify.com/update_payment/#{subscriber_id}/#{self.secure_digest(["update_payment", subscriber_id, self.site_key].join("--"))[0..9]}"
end
private
def self.chargify_config
YAML::load_file(File.join(Rails.root, 'config', 'chargify.yml'))
end
def self.site_key
self.chargify_config[Rails.env]['site_key']
end
def self.subdomain
self.chargify_config[Rails.env]['subdomain']
end
def self.product_id(plan)
# your own logic to retrieve the Chargify product ID for
# the plan in question (hint: I store mine in the DB)
end
end
class RegistrationsController < PublicController
# ...
def create
@plan, @user = Plan.find_by_name(params[:plan]), User.new(params[:user])
@user.save!
# check if they've selected a Free plan
if @plan.does_not_require_credit_card_yet?
@user.reload.create_subscription_and_setup_account!(@plan)
redirect_to new_session_path
else
# redirect to http://chargify.com ================>
redirect_to PaymentProcessor.hosted_signup_page_for(@plan, @user)
end
rescue ActiveRecord::RecordInvalid
render :new
end
# ...
end
class User < ActiveRecord::Base
# ...
def create_subscription_and_setup_account!(plan)
json_data = {
:subscription => {
:product_id => # [your logic for getting product ID],
:customer_attributes => {
:first_name => self.first_name,
:last_name => self.last_name,
:email => self.email,
:reference => self.token
}
}
}
subscription = Chargify::Subscription.create(json_data[:subscription])
Account.init!(subscription) unless subscription.blank?
end
# ...
end
def CompleteRegistrationsController < PublicController
def new
subscription = Chargify::Subscription.find(params[:subscription].to_i) rescue nil
Account.init!(subscription) if subscription.present?
end
end
class Account < ActiveRecord::Base
belongs_to :user
belongs_to :plan
# these states are those that Chargify considers to be safe, meaning
# your users should still be able to login to your application
ACTIVE_STATES = ['pending', 'trialing', 'assessing', 'active', 'soft_failure', 'past_due']
# ...
# this method will almost always be unique to the application itself,
# but I wanted to show an example implementation just in case it's useful
def self.init!(subscription, account_state = 'pending')
user_token = subscription.customer.reference if subscription.customer
product_handle = subscription.product.handle if subscription.product
if user_token && product_handle
user = User.find_by_token(user_token)
unless user.activated?
user.setup_account(Plan.find_by_name(product_handle), :state => account_state)
user.apply_default_settings
user.activate!
end
end
end
# a series of example convenience methods.....
def chargify_subscriber_id
@subscriber_id ||= Chargify::Subscription.find_by_customer_reference(self.user.token).id
end
def active?
ACTIVE_STATES.include?(self.state) || self.exempt?
end
def inactive?
!self.active?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment