Skip to content

Migrate from Stripe Charges API to Stripe Checkout Sessions API#58

Merged
li-xinwei merged 8 commits intomainfrom
stripe-checkout-migration
Mar 29, 2026
Merged

Migrate from Stripe Charges API to Stripe Checkout Sessions API#58
li-xinwei merged 8 commits intomainfrom
stripe-checkout-migration

Conversation

@li-xinwei
Copy link
Copy Markdown

@li-xinwei li-xinwei commented Mar 5, 2026

Summary

  • Migrate payment processing from the legacy Stripe Charges API (Stripe::Charge.create) and embedded Checkout.js to the modern Stripe Checkout Sessions API (Stripe::Checkout::Session.create)
  • Redirect users to Stripe's hosted checkout page for a more secure payment experience with built-in support for SCA/3D Secure, Apple Pay, Google Pay, and other payment methods
  • Send itemized ticket breakdown as line_items to Stripe instead of only the total cost, improving payment tracking and reconciliation on both the Stripe Dashboard and customer receipts
  • Add stripe_session_id to the payments table for better payment tracking and session-based verification

Changes

Payment Model (app/models/payment.rb)

  • Replaced purchase method (which used Stripe::Charge.create) with:
    • create_checkout_session — creates a Stripe Checkout Session with itemized line items and redirects to Stripe
    • complete_checkout — retrieves the session after redirect, verifies payment status, and records charge details
  • Added build_line_items private method that maps each unpaid TicketPurchase to a Stripe line item with proper currency conversion
  • Added unpaid_ticket_purchases helper method

Payments Controller (app/controllers/payments_controller.rb)

  • create action now creates a Payment record and Stripe Checkout Session, then redirects to Stripe's hosted page
  • Added success action — handles the return from Stripe after successful payment, verifies the session, marks tickets as paid, and handles registration
  • Added cancel action — handles payment cancellation, redirects back to payment page
  • Removed dependency on stripeToken/stripeEmail params (no longer needed with hosted checkout)

Routes (config/routes.rb)

  • Added success and cancel collection routes under payments

Views

  • Replaced legacy Stripe Checkout.js <script> tag with a standard form submit button that initiates the checkout flow
  • Updated payment summary page messaging to indicate redirect to Stripe

Database

  • Migration to add stripe_session_id (string, unique index) to payments table
  • Updated db/schema.rb

Tests

  • Updated spec/models/payment_spec.rb to test create_checkout_session and complete_checkout methods using RSpec mocks
  • Updated spec/features/ticket_purchases_spec.rb to work with the new checkout flow

Test plan

  • Verify that selecting tickets and clicking "Pay" creates a Stripe Checkout Session and redirects to Stripe
  • Verify successful payment redirects back with confirmation and marks tickets as paid
  • Verify cancelled payment redirects back to payment page with appropriate message
  • Verify itemized ticket details appear correctly on the Stripe Checkout page
  • Verify registration ticket flow still works (auto-registration after payment)
  • Verify free ticket purchases are unaffected
  • Verify currency conversion works correctly in checkout line items
  • Run bundle exec rspec spec/models/payment_spec.rb
  • Run bundle exec rspec spec/features/ticket_purchases_spec.rb

@Ethan-Stone1
Copy link
Copy Markdown

Can you fix the rubocop errors please

Replace the legacy Stripe Charges API and embedded Checkout.js with
the modern Stripe Checkout Sessions API. This redirects users to
Stripe's hosted checkout page for a more secure and flexible payment
experience.

Key changes:
- Payment model: replace Stripe::Charge.create with
  Stripe::Checkout::Session.create and session verification
- Send itemized ticket breakdown as line_items to Stripe instead of
  only the total cost, improving payment tracking and reconciliation
- Add stripe_session_id column to payments table for session tracking
- Add success/cancel callback routes for Stripe redirect flow
- Update payment views to use standard form submission instead of
  embedded Stripe Checkout.js
- Update tests to use RSpec mocks for Checkout Session API
Move errors.add after save to prevent ActiveRecord from clearing
the error messages when the record is successfully saved.
- Fix RSpec/MessageSpies: use argument capture pattern instead of
  have_received to satisfy both MessageSpies and StubbedMock cops
- Add test files to RSpec/VerifiedDoubles exclude list since Stripe
  API objects use dynamic attributes incompatible with instance_double
- Fix pre-existing Style/NumericPredicate in config/puma.rb
- Fix pre-existing RSpec/PendingWithoutReason in organization_spec.rb
- Fix pre-existing Layout/SpaceInsidePercentLiteralDelimiters in Gemfile
The organization validation and association tests actually pass.
Changed from xit/pending to regular test assertions.
- Move Pay button to the right side using flexbox layout
- Remove btn-lg from Pay button to match Edit Purchase button size
- Wrap buttons in .payment-actions container for consistent spacing
The ticket table was wrapped in .div > .col-md-12 which caused the
form buttons to float beside the table instead of appearing below it.

- Remove unnecessary .div and .col-md-12 wrapper
- Use .table-responsive directly as the table container
- Buttons now correctly appear below the table in a flex row

Fixes #67
The _form_fields partial uses Devise's resource variable, which is
not available when rendered in non-Devise contexts like proposals/new.
Add defined?(resource) guard to prevent NameError.
@li-xinwei li-xinwei force-pushed the stripe-checkout-migration branch from 90103d9 to e3f3ba6 Compare March 29, 2026 01:51
@li-xinwei li-xinwei merged commit 8f5adc5 into main Mar 29, 2026
11 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants