React+Rails电商项目Stripe支付控制器跳转报错求助
Hey there! Let's break down what's going on with your React + Rails e-commerce setup and that tricky redirect issue with the Stripe charges controller. I’ve run into similar headaches with SPA-Rails integrations before, so let’s walk through the fixes step by step.
The Core Problem: AJAX + Rails Redirects Don’t Play Nice
When you send a fetch request (which is an AJAX call) to your charges#create action, Rails tries to redirect with redirect_to new_charge_path—but browsers don’t automatically handle this redirect for AJAX requests. Instead, the fetch call will receive the response from charges#new directly, but your React app isn’t set up to process that response, leading to errors.
Fix 1: Ditch Traditional Redirects for JSON Responses (Recommended for SPAs)
Instead of having Rails handle the redirect, return a JSON response from create and let React manage the navigation or state update. This is the cleanest approach for single-page apps.
Update Your Rails ChargesController:
class ChargesController < ApplicationController def create begin # Process Stripe charge here charge = Stripe::Charge.create( amount: params[:amount], currency: 'usd', source: params[:stripe_token], description: params[:description] ) # If successful, return success status and redirect URL render json: { status: :success, redirect_url: new_charge_path }, status: :ok rescue Stripe::CardError => e # Handle payment failures by returning errors @charge = Charge.new(charge_params) @charge.errors.add(:base, e.message) render json: { errors: @charge.errors.full_messages }, status: :unprocessable_entity end end def new @charge = Charge.new respond_to do |format| format.html format.json { render json: @charge } # Ensure JSON is supported here end end private def charge_params params.permit(:amount, :description, :stripe_token) end end
Update Your React Fetch Logic:
Handle the JSON response to either redirect or display errors:
const handlePaymentSubmit = async (chargeData) => { try { const response = await fetch('/charges', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify(chargeData) }); const data = await response.json(); if (data.status === 'success') { // Redirect to the new charge page (use React Router if it's an SPA route) window.location.href = data.redirect_url; // Or for React Router: history.push(data.redirect_url); } else { // Display error messages to the user alert(`Payment failed: ${data.errors.join(', ')}`); } } catch (error) { console.error('Request error:', error); } };
Fix 2: If You Must Keep Rails Redirects (Not Ideal for SPAs)
If you need to stick with redirect_to, you’ll need to make sure fetch follows the redirect and your new action handles the request properly.
Ensure charges#new Responds to JSON:
def new # Pull parameters from session if you need to persist data across redirects @charge = Charge.new(session[:charge_params] || {}) session.delete(:charge_params) # Clean up after use respond_to do |format| format.html format.json { render json: @charge } end end
Update charges#create to Store Params in Session:
Since AJAX redirects don’t carry POST params, use the session to pass data to new:
def create @charge = Charge.new(charge_params) if @charge.invalid? session[:charge_params] = charge_params redirect_to new_charge_path, status: :see_other else # Process Stripe charge... end end
Adjust Fetch to Handle Redirects:
Fetch follows redirects by default, but you’ll need to process the final response from charges#new:
fetch('/charges', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify(chargeData) }) .then(response => { // Check if we were redirected if (response.redirected) { return response.json(); // Get the new charge data from the redirected response } return response.json(); }) .then(data => { // Use the @charge data from charges#new to update your React state console.log('New charge data:', data); }) .catch(error => console.error('Error:', error));
Quick Check for Nil Params
If your params are coming through as nil in charges#new, double-check:
- You’re permitting all required parameters in
charge_params - The React app is correctly stringifying the data in the fetch body
- You’re using
session[:charge_params]to persist data across redirects (if using that approach)
内容的提问来源于stack exchange,提问作者Corina Feraru

