Skip to content

Instantly share code, notes, and snippets.

@excid3
Created October 19, 2017 15:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save excid3/0772b783004c63c182d0e669b0b5c68b to your computer and use it in GitHub Desktop.
Save excid3/0772b783004c63c182d0e669b0b5c68b to your computer and use it in GitHub Desktop.
Stripe Payments Course: Requiring payments upfront
From e0e025f141ad50ca83c729f26a2035cf2f214262 Mon Sep 17 00:00:00 2001
From: Chris Oliver <excid3@gmail.com>
Date: Wed, 1 Feb 2017 17:19:12 -0600
Subject: [PATCH] Add stripe payments as required for registration
---
Gemfile | 1 +
Gemfile.lock | 5 +-
app/assets/javascripts/payments.js | 39 ++++++++++++++
app/controllers/application_controller.rb | 7 ++-
app/controllers/users/registrations_controller.rb | 23 +++++++++
app/models/user.rb | 20 +++++++
app/views/devise/registrations/new.html.erb | 63 +++++++++++++++++------
app/views/layouts/application.html.erb | 4 +-
config/initializers/stripe.rb | 1 +
config/routes.rb | 2 +-
db/migrate/20170201222632_add_stripe_to_users.rb | 6 +++
db/schema.rb | 4 +-
12 files changed, 153 insertions(+), 22 deletions(-)
create mode 100644 app/assets/javascripts/payments.js
create mode 100644 app/controllers/users/registrations_controller.rb
create mode 100644 config/initializers/stripe.rb
create mode 100644 db/migrate/20170201222632_add_stripe_to_users.rb
diff --git a/Gemfile b/Gemfile
index 37cb605..4fe1b3d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -64,6 +64,7 @@ gem 'paranoia', '~> 2.2.0'
gem 'sidekiq', '~> 4.2', '>= 4.2.7'
gem 'sshkey', '~> 1.8'
gem 'sshkit', '~> 1.11', '>= 1.11.4'
+gem 'stripe', '~> 1.58'
source 'https://rails-assets.org' do
gem 'rails-assets-tether', '>= 1.1.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index e3a77f1..9588f79 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -300,6 +300,8 @@ GEM
sshkit (1.11.5)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
+ stripe (1.58.0)
+ rest-client (>= 1.4, < 4.0)
thor (0.19.4)
thread_safe (0.3.5)
tilt (2.0.5)
@@ -366,10 +368,11 @@ DEPENDENCIES
spring-watcher-listen (~> 2.0.0)
sshkey (~> 1.8)
sshkit (~> 1.11, >= 1.11.4)
+ stripe (~> 1.58)
turbolinks (~> 5)
tzinfo-data
uglifier (>= 1.3.0)
web-console
BUNDLED WITH
- 1.13.7
+ 1.14.3
diff --git a/app/assets/javascripts/payments.js b/app/assets/javascripts/payments.js
new file mode 100644
index 0000000..8f77b97
--- /dev/null
+++ b/app/assets/javascripts/payments.js
@@ -0,0 +1,39 @@
+$(document).on("turbolinks:load", function() {
+ key = $("meta[name='stripe-public-key']").attr("content");
+ Stripe.setPublishableKey(key);
+
+ var $form = $('.payment-form');
+ $form.submit(function(event) {
+ // Disable the submit button to prevent repeated clicks:
+ $form.find('.submit').prop('disabled', true);
+
+ // Request a token from Stripe:
+ Stripe.card.createToken($form, stripeResponseHandler);
+
+ // Prevent the form from being submitted:
+ return false;
+ });
+});
+
+function stripeResponseHandler(status, response) {
+ // Grab the form:
+ var $form = $('.payment-form');
+
+ if (response.error) { // Problem!
+
+ // Show the errors on the form:
+ $form.find('.payment-errors').text(response.error.message);
+ $form.find('.submit').prop('disabled', false); // Re-enable submission
+
+ } else { // Token was created!
+
+ // Get the token ID:
+ var token = response.id;
+
+ // Insert the token ID into the form so it gets submitted to the server:
+ $form.append($('<input type="hidden" name="user[stripe_card_token]">').val(token));
+
+ // Submit the form:
+ $form.get(0).submit();
+ }
+};
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 66ba867..02ebc1c 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,8 +1,14 @@
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
+ before_action :configure_permitted_parameters, if: :devise_controller?
+
private
+ def configure_permitted_parameters
+ devise_parameter_sanitizer.permit(:sign_up, keys: [:stripe_card_token])
+ end
+
def authenticate_user_from_token!
auth_token = params[:auth_token].presence
user = auth_token && User.find_by_auth_token(auth_token.to_s)
@@ -15,4 +21,3 @@ def authenticate_user_from_token!
sign_in user, store: false
end
end
-end
diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb
new file mode 100644
index 0000000..b3d8b6c
--- /dev/null
+++ b/app/controllers/users/registrations_controller.rb
@@ -0,0 +1,23 @@
+class Users::RegistrationsController < Devise::RegistrationsController
+ def create
+ build_resource(sign_up_params)
+
+ resource.save_with_payment
+ yield resource if block_given?
+ if resource.persisted?
+ if resource.active_for_authentication?
+ set_flash_message! :notice, :signed_up
+ sign_up(resource_name, resource)
+ respond_with resource, location: after_sign_up_path_for(resource)
+ else
+ set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
+ expire_data_after_sign_in!
+ respond_with resource, location: after_inactive_sign_up_path_for(resource)
+ end
+ else
+ clean_up_passwords resource
+ set_minimum_password_length
+ respond_with resource
+ end
+ end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 1e34741..12e2f86 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -7,6 +7,10 @@ class User < ApplicationRecord
has_many :servers
has_many :apps, through: :servers
+ attribute :stripe_card_token, :string
+
+ validates :stripe_card_token, presence: true, on: :create
+
def ssh_keys
services.source_control.map do |service|
[
@@ -15,4 +19,20 @@ def ssh_keys
]
end
end
+
+ def save_with_payment
+ if valid?
+ # try to create stripe customer with subscription
+ stripe_customer = Stripe::Customer.create(source: stripe_card_token, email: email, plan: "individual-19")
+ update(
+ stripe_customer_id: stripe_customer.id,
+ stripe_subscription_id: stripe_customer.subscriptions.first.id,
+ trial_end: stripe_customer.subscriptions.first.trial_end
+ )
+ else
+ false
+ end
+ rescue Stripe::CardError => e
+ errors.add(:base, e.message)
+ end
end
diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb
index 7a45d97..248b9bf 100644
--- a/app/views/devise/registrations/new.html.erb
+++ b/app/views/devise/registrations/new.html.erb
@@ -1,28 +1,59 @@
<div class="row">
<div class="col-sm-4 offset-sm-4">
- <h1 class="text-center">Sign Up</h1>
- <hr>
+ <h2 class="text-center">Sign Up</h2>
- <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
+ <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: {class: "payment-form"}) do |f| %>
<%= devise_error_messages! %>
- <div class="form-group">
- <%= f.label :email %><br />
- <%= f.email_field :email, autofocus: false, class: 'form-control' %>
- </div>
+ <div class="card card-block mb-3">
+ <h4>1. Account Details</h4>
- <div class="form-group">
- <%= f.label :password %>
- <% if @minimum_password_length %>
- <em>(<%= @minimum_password_length %> characters minimum)</em>
- <% end %><br />
- <%= f.password_field :password, autocomplete: "off", class: 'form-control' %>
+ <div class="form-group">
+ <%= f.label :email %><br />
+ <%= f.email_field :email, autofocus: false, class: 'form-control' %>
+ </div>
+
+ <div class="form-group">
+ <%= f.label :password %>
+ <% if @minimum_password_length %>
+ <em>(<%= @minimum_password_length %> characters minimum)</em>
+ <% end %><br />
+ <%= f.password_field :password, autocomplete: "off", class: 'form-control' %>
+ </div>
+
+ <div class="form-group">
+ <%= f.label :password_confirmation %><br />
+ <%= f.password_field :password_confirmation, autocomplete: "off", class: 'form-control' %>
+ </div>
</div>
- <div class="form-group">
- <%= f.label :password_confirmation %><br />
- <%= f.password_field :password_confirmation, autocomplete: "off", class: 'form-control' %>
+ <div class="card card-block mb-3">
+ <h4>2. Billing Information</h4>
+ <span class="payment-errors"></span>
+
+ <div class="form-row">
+ <label>
+ <span>Card Number</span>
+ <input type="text" size="20" data-stripe="number">
+ </label>
+ </div>
+
+ <div class="form-row">
+ <label>
+ <span>Expiration (MM/YY)</span>
+ <input type="text" size="2" data-stripe="exp_month">
+ </label>
+ <span> / </span>
+ <input type="text" size="2" data-stripe="exp_year">
+ </div>
+
+ <div class="form-row">
+ <label>
+ <span>CVC</span>
+ <input type="text" size="4" data-stripe="cvc">
+ </label>
+ </div>
</div>
<div class="form-group">
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 022268d..11df467 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -5,10 +5,10 @@
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
- <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+ <%= javascript_include_tag 'application', 'https://js.stripe.com/v2/', 'data-turbolinks-track': 'reload' %>
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
+ <%= tag :meta, name: "stripe-public-key", content: Rails.application.secrets.stripe_public_key %>
</head>
-
<body>
<%= render partial: "shared/navbar" %>
diff --git a/config/initializers/stripe.rb b/config/initializers/stripe.rb
new file mode 100644
index 0000000..555cc16
--- /dev/null
+++ b/config/initializers/stripe.rb
@@ -0,0 +1 @@
+Stripe.api_key = Rails.application.secrets.stripe_secret_key
diff --git a/config/routes.rb b/config/routes.rb
index e881776..abfeaf6 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -16,7 +16,7 @@
mount Sidekiq::Web => '/sidekiq'
end
- devise_for :users, controllers: {omniauth_callbacks: "users/omniauth_callbacks"}
+ devise_for :users, controllers: {registrations: "users/registrations", omniauth_callbacks: "users/omniauth_callbacks"}
resources :servers do
collection do
diff --git a/db/migrate/20170201222632_add_stripe_to_users.rb b/db/migrate/20170201222632_add_stripe_to_users.rb
new file mode 100644
index 0000000..3980c6f
--- /dev/null
+++ b/db/migrate/20170201222632_add_stripe_to_users.rb
@@ -0,0 +1,6 @@
+class AddStripeToUsers < ActiveRecord::Migration[5.0]
+ def change
+ add_column :users, :stripe_customer_id, :string
+ add_column :users, :stripe_subscription_id, :string
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 997dbd5..e4263a0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170119195509) do
+ActiveRecord::Schema.define(version: 20170201222632) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -101,6 +101,8 @@
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "auth_token"
+ t.string "stripe_customer_id"
+ t.string "stripe_subscription_id"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment