# Terminal
rails g scaffold product name 'price:decimal{8,2}' quantity:integer
rails g migration add_fields_to_users stripe_id:string vbuck:integer
brew install ngrok
ngrok http 3000
# views/layouts/application.html.erb
<%= tag :meta, name: 'stripe-public-key', content: ENV['STRIPE_PUBLIC_KEY'] %>
<%= javascript_include_tag 'https://js.stripe.com/v3/', 'data-turbolinks-track': 'reload' %>
# config/environments/development.rb
config.hosts = nil
# config/initializers/stripe.rb
Stripe.api_key = ENV['STRIPE_API_KEY']
StripeEvent.signing_secret = ENV['STRIPE_SIGNING_SECRET']
StripeEvent.configure do |config|
config.subscribe 'checkout.session.completed' do |event|
PaymentReceived.call(event)
end
end
# views/products/index.html.erb
<%= link_to 'Buy Now', purchases_path(product_id: product.id), method: :post, remote: true %>
# routes.rb
resource :purchases, only: :create
mount StripeEvent::Engine, at: '/stripe/webhook'
# purchases_controller.rb
class PurchasesController < ApplicationController
before_action :authenticate_user!
def create
session = Stripe::Checkout::Session.create(stripe_parameters)
@session_id = session.id
end
private
def stripe_parameters
{}.tap do |json|
json[:payment_method_types] = ['card']
json[:customer] = current_user.stripe_id if current_user.stripe_id
json[:client_reference_id] = current_user.id unless current_user.stripe_id
json[:customer_email] = current_user.email unless current_user.stripe_id
json[:allow_promotion_codes] = true
json[:line_items] = line_items
json[:success_url] = 'http://localhost:3000/'
json[:cancel_url] = 'http://localhost:3000/'
end
end
def line_items
[].tap do |array|
products.each do |product|
array << {
quantity: 1,
name: product.name,
amount: (product.price * 100).to_i,
currency: 'USD',
description: product.name
}
end
end
end
def products
Product.where(id: params[:product_id])
end
end
# views/purchases/create.js.erb
stripe_publishable_key = document.querySelector('meta[name="stripe-public-key"]').getAttribute('content')
stripe = Stripe(stripe_publishable_key)
stripe.redirectToCheckout({
sessionId: "<%= @session_id %>"
})
# models/payment_received.rb
class PaymentReceived
def self.call(event)
new(event).call
end
attr_reader :event
def initialize(event)
@event = event
end
def call
return unless user
user.update(stripe_id: object.customer) unless user.stripe_id
complete_purchase
end
private
def user
@user ||= if object.client_reference_id
User.find_by(id: object.client_reference_id)
else
User.find_by(stripe_id: object.customer)
end
end
def object
@object ||= event.data.object
end
def complete_purchase
line_items.each do |item|
product = Product.find_by(name: item.description)
total = product.quantity * item.quantity
user.update(vbuck: user.vbuck.to_i + total)
end
end
def line_items
Stripe::Checkout::Session.list_line_items(object.id).data
end
end