Skip to content

Instantly share code, notes, and snippets.

@ciaranha
Last active August 29, 2015 14:14
Show Gist options
  • Save ciaranha/1a18ed57d9079aced43b to your computer and use it in GitHub Desktop.
Save ciaranha/1a18ed57d9079aced43b to your computer and use it in GitHub Desktop.
Stripe & Rails Subscriptions
#/app/services/create_subscription.rb
class CreateSubscription
def self.call(plan, email_address, token)
user, raw_token = CreateUser.call(email_address)
subscription = Subscription.new(
plan: plan,
user: user
)
begin
stripe_sub = nil
if user.stripe_customer_id.blank?
customer = Stripe::Customer.create(
card: token,
email: user.email,
plan: plan.stripe_id,
)
user.stripe_customer_id = customer.id
user.save!
stripe_sub = customer.subscriptions.first
else
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
stripe_sub = customer.subscriptions.create(
plan: plan.stripe_id
)
end
subscription.stripe_id = stripe_sub.id
subscription.save!
rescue Stripe::StripeError => e
subscription.errors[:base] << e.message
end
subscription
end
end
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: 5
development:
<<: *default
database: sales_development
test:
<<: *default
database: sales_test
production:
<<: *default
database: sales_production
username: sales
password: <%= ENV['SALES_DATABASE_PASSWORD'] %>
# app/models/plan.rb
class Plan < ActiveRecord::Base
has_paper_trail
validates :stripe_id, uniqueness: true
end
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140307141707) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "affiliates", force: true do |t|
t.string "code"
t.string "email"
t.integer "percent"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "coupons", force: true do |t|
t.string "code"
t.integer "percent_off"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "coupons", ["user_id"], name: "index_coupons_on_user_id", using: :btree
create_table "events", force: true do |t|
t.string "stripe_id"
t.string "stripe_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "events", ["stripe_id", "stripe_type"], name: "index_events_on_stripe_id_and_stripe_type", using: :btree
create_table "products", force: true do |t|
t.string "name"
t.string "permalink"
t.text "description"
t.integer "price"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.text "download_url"
t.string "file_file_name"
t.string "file_content_type"
t.integer "file_file_size"
t.datetime "file_updated_at"
end
add_index "products", ["user_id"], name: "index_products_on_user_id", using: :btree
create_table "sales", force: true do |t|
t.string "email"
t.string "guid"
t.integer "product_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "state"
t.string "stripe_id"
t.string "stripe_token"
t.string "card_last4"
t.date "card_expiration"
t.string "card_type"
t.text "error"
t.integer "amount"
t.integer "fee_amount"
t.integer "coupon_id"
t.boolean "opt_in"
t.integer "download_count"
t.integer "affiliate_id"
t.text "customer_address"
end
add_index "sales", ["coupon_id"], name: "index_sales_on_coupon_id", using: :btree
add_index "sales", ["product_id"], name: "index_sales_on_product_id", using: :btree
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "versions", force: true do |t|
t.string "item_type", null: false
t.integer "item_id", null: false
t.string "event", null: false
t.string "whodunnit"
t.text "object"
t.datetime "created_at"
t.text "object_changes"
end
add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id", using: :btree
end
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :plan
has_paper_trail
end
@ciaranha
Copy link
Author

CreatePlan.call(stripe_id: 'test_plan', name: 'Test Plan', amount: 500, interval: 'month', description: 'Test Plan', published: false)
PG::UndefinedTable: ERROR: relation "plans" does not exist
LINE 5: WHERE a.attrelid = '"plans"'::regclass ^ : SELECT a.attname, format_type(a.atttypid, a.atttypmod), pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"plans"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum

@MarkMurphy
Copy link

can I see your plan model and can you confirm that you have a plans table in your database?

@MarkMurphy
Copy link

k, lets see your db/schema.rb

@ciaranha
Copy link
Author

You get that file? Was just sticking it in as you asked. Thanks again for having a look.

@MarkMurphy
Copy link

Looks like you're missing the plans table. Try running this in your terminal: bundle exec rake db:migrate

@ciaranha
Copy link
Author

OK right. That gives me
PG::DuplicateTable: ERROR: relation "users" already exists : CREATE TABLE "users"
I've been round in circles today and tried different things to sort out this issue
rake db:drop:all
rake db:create:all
rake db:migrate
etc but not really sure of the root of the problem!

@MarkMurphy
Copy link

try rake db:migrate:reset

@ciaranha
Copy link
Author

I've tried
rake db:migrate:reset
rails c
CreatePlan.call(stripe_id: 'test_plan', name: 'Test Plan', amount: 500, interval: 'month', description: 'Test Plan', published: false)
and I'm still getting

PG::UndefinedTable: ERROR: relation "plans" does not exist

Should I start the tutorial again?!

@MarkMurphy
Copy link

hmm, seems like it's still missing the plans table. Do you see this file in your db/migrate folder: 20130623004957_create_plans.rb?

What output do you get after running this command: rake db:version
and this command: rake db:migrate:status

@ciaranha
Copy link
Author

rake db:version Current version: 20130706050148

@ciaranha
Copy link
Author

Ciarans-MacBook-Pro-2:sales ciaranhanrahan$ rake db:migrate:status

database: sales_development

Status Migration ID Migration Name

up 20130601181623 ********** NO FILE **********
up 20130601181655 ********** NO FILE **********
up 20130601183433 ********** NO FILE **********
up 20130603002956 ********** NO FILE **********
up 20130608172149 ********** NO FILE **********
up 20130608175304 ********** NO FILE **********
up 20130608175305 ********** NO FILE **********
up 20130613043735 ********** NO FILE **********
up 20130623002854 ********** NO FILE **********
up 20130623004920 ********** NO FILE **********
up 20130628020156 ********** NO FILE **********
up 20130706042420 ********** NO FILE **********
up 20130706050148 ********** NO FILE **********
down 20150126140949 Devise create users
down 20150126141656 Create products
down 20150126142017 Add attachment file to products
down 20150126142729 Create sales
down 20150126161529 Add fields to sale
down 20150126162502 Create versions
down 20150126162503 Add object changes to versions
down 20150126171301 Create stripe webhooks
down 20150126173642 Create plans
down 20150126173810 Create subscriptions
down 20150126173830 Add stripe customer id to user
down 20150127091517 Create invoice payments

@ciaranha
Copy link
Author

and yea I have db/migrate/20150126173642_create_plans.rb

@ciaranha
Copy link
Author

ooh new error!
Migrations are pending. To resolve this issue, run: bin/rake db:migrate RAILS_ENV=development and when I run that I get this
ActiveRecord::StatementInvalid: PG::DuplicateTable: ERROR: relation "users" already exists.

If I was to start this tutorial again is there a way I can start with a clean slate regarding databases?!

@MarkMurphy
Copy link

can you send me a screenshot or a list of the files that are in your db/migrate folder?

@ciaranha
Copy link
Author

migrate/
20150126140949_devise_create_users.rb
20150126141656_create_products.rb
20150126142017_add_attachment_file_to_products.rb
20150126142729_create_sales.rb
20150126161529_add_fields_to_sale.rb
20150126162503_add_object_changes_to_versions.rb
20150126171301_create_stripe_webhooks.rb
20150126173642_create_plans.rb
20150126173810_create_subscriptions.rb
20150126173830_add_stripe_customer_id_to_user.rb
20150127091517_create_invoice_payments.rb

@MarkMurphy
Copy link

That definitely doesn't look right. Did you start a new rails project or are you working out of the sample code project?

If you're using the sample code, you should see this list:

20130601181623_devise_create_users.rb
20130601181655_create_products.rb
20130601183433_create_sales.rb
20130603002956_add_download_url_to_product.rb
20130608172149_add_fields_to_sale.rb
20130608175304_create_versions.rb
20130608175305_add_object_changes_column_to_versions.rb
20130613043735_add_indexes.rb
20130623002854_devise_create_members.rb
20130623004920_add_stripe_id_to_member.rb
20130623004957_create_plans.rb
20130623005003_create_subscriptions.rb
20130628020156_add_attachment_file_to_products.rb
20130706042420_create_coupons.rb
20130706050148_add_coupon_to_sale.rb
20130706165509_drop_plan_and_subscription.rb
20130706190446_add_indexes_to_coupons_and_sales.rb
20130706215713_create_events.rb
20130707194426_add_opt_in_to_sale.rb
20130707200130_add_index_for_events.rb
20130809023122_add_download_counter_to_sales.rb
20130910214925_change_card_expiration_to_date.rb
20130922023327_create_affiliates.rb
20130922030850_add_affiliate_id_to_sale.rb
20140307141707_add_customer_address_to_sale.rb
20140526173650_add_show_business_address_to_sale.rb

@ciaranha
Copy link
Author

OK I'm missing a lot. I started a brand new project and followed the tutorial. I didn't start from the the code sample. So I guess go from the beginning but with the code sample is the best thing to do from here?

@MarkMurphy
Copy link

@Jaibles I would download the code sample again to make sure you have the most up-to-date version. If you're relatively new to ruby on rails I would highly recommend checking out the rails tutorial book if you haven't already. Codeschool.com has some great resources too if you're interested. They'll definitely help in the future!

@MarkMurphy
Copy link

Also, make sure you drop the existing sales_development and sales_test databases before you setup the new code base

@ciaranha
Copy link
Author

Hi @MarkMurphy,

I've gone back through and am using the code sample. At the same point I was having the issue yesterday I am getting

Ciarans-MacBook-Pro-2:sales ciaranhanrahan$ rake db:migrate
== 20130706165509 DropPlanAndSubscription: migrating ==========================
-- drop_table(:subscriptions)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  table "subscriptions" does not exist
: DROP TABLE "subscriptions"/Users/ciaranhanrahan/.rvm/gems/ruby-2.1.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `async_exec'

Should my schema.rb have a create_subscriptions table at this point and how do I get the migrations feature of active records to modify this file, or why hasn't it done so already?

(Totally understand if you don't have any more time for this issue!)

@MarkMurphy
Copy link

If all earlier migrations were applied successfully then yes you should have a subscriptions table. If you look in the migrations folder you will see that it creates that table in 20130623005003_create_subscriptions.rb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment