# 2026 年 Rails 支付：超越 Stripe

> 面向 Ruby on Rails 应用的现代支付集成。从 Stripe 转向 MoR（名义商户），享受更简单的计费、自动税务合规和全球支付支持。
- **Author**: Ayush Agarwal
- **Published**: 2026-03-29
- **Category**: Payments, Developer Tools, How-To
- **URL**: https://dodopayments.com/blogs/zh/rails-payments-beyond-stripe

---

十多年来，对于任何希望接受付款的 Ruby on Rails 开发者来说，默认答案都是 Stripe。这一组合堪称传奇：Rails 提供生产力和约定，而 Stripe 提供 API 优先的支付基础设施。它们简直是开发者天堂般的完美搭配。你只需引入像 `pay` 或 `stripe-ruby` 这样的 gem，设置几个 webhook，就可以开始营业了。

但进入 2026 年后，市场格局已经发生了变化。2015 年那种"简单"的支付集成，如今已经演变成由全球税务合规、多地区计费法规和复杂的收入追回需求组成的网络。过去一个周末就能完成的项目，现在需要专门的团队来处理欧盟 VAT、美国销售税，以及不断变化的全球支付方式等边界情况。

对于重视"约定优于配置"理念的 Rails 开发者来说，传统支付网关模式开始让人感觉配置繁多，却几乎没有约定可言。这正是 MoR（名义商户）模式发挥作用的地方。通过从 Stripe 转向 Dodo Payments 这样的 MoR（名义商户），你可以将税务、合规和计费复杂性的全部负担交出去，把精力集中在 Rails 最擅长的事情上：构建你的应用。

## 网关模式隐藏的复杂性

当你使用 Stripe 这样的传统支付网关时，你就是"名义商户"。这意味着你要对每笔交易承担法律责任。Stripe 负责信用卡的技术处理，但以下事项都由你负责：

> 创业者在设置支付时犯的最大错误，是把它当成一个已经解决的问题。你接入一个网关，添加一个结账按钮，然后以为大功告成。六个月后，你却要处理税务通知、续费失败，以及由于缺少本地支付方式而导致的结账放弃。
>
> \- Ayush Agarwal，Dodo Payments 联合创始人兼 CPTO

- **全球税务合规**：在所有拥有客户的司法管辖区计算、收取并缴纳销售税、VAT 和 GST。
- **计费基础设施**：构建并维护计费门户，让用户可以更新卡片、查看发票和管理订阅。
- **催收与追回**：处理付款失败、卡片过期，以及决定何时重试扣款的复杂逻辑。
- **合规与安全**：管理 PCI 合规、KYC（了解你的客户）要求和风险防控。

对于小团队或个人创业者来说，这是一项巨大的额外负担。你创建 Rails 应用是为了解决特定问题，而不是成为国际税法专家。

## Rails 开发者为何喜欢 MoR（名义商户）模式

Ruby on Rails 的理念建立在这样一个原则之上：开发者应该专注于独特的业务逻辑，而框架负责处理那些"无聊"的事情。我们使用 ActiveRecord，这样就不必编写原始 SQL；我们使用 ActionMailer，这样就不必管理 SMTP 服务器。

MoR（名义商户）是这一理念在支付领域的自然延伸。你不再亲自充当商户，而是由 MoR（名义商户）作为你软件的法定销售方。他们负责税务、合规和计费门户。你只需提供产品和价格。

正是因为与 Rails 的核心价值观高度一致，越来越多的开发者开始寻找能够提供更一体化、"开箱即用"体验的 [Stripe 替代方案](https://dodopayments.com/blogs/stripe-alternatives)。

## 现代 Rails 支付集成的架构

在传统设置中，你的 Rails 应用处于复杂服务网络的中心。使用 MoR（名义商户）后，架构会大幅简化。

```mermaid
flowchart TD
    User[User] -->|1. Clicks Buy| Rails[Rails App]
    Rails -->|2. Creates Session| MoR[Dodo Payments]
    MoR -->|3. Handles Checkout| User
    MoR -->|4. Processes Tax & Payment| Gateway[Global Banks]
    MoR -->|5. Sends Webhook| Rails
    Rails -->|6. Provisions Access| User
```

MoR（名义商户）负责交易中的繁重工作，包括 [嵌入式支付](https://dodopayments.com/blogs/embedded-payments-saas) 体验，而你的 Rails 应用仍然是用户访问权限和应用状态的事实来源。

## 分步指南：在 Rails 中集成 Dodo Payments

下面来了解一个现代化的集成流程。我们将从一个干净的 Rails 8 应用开始，构建一个功能完整且符合税务要求的订阅系统。

### 1. 设置与配置

首先，我们需要将 Dodo Payments gem 添加到 `Gemfile` 中。虽然你也可以使用通用 HTTP 客户端，但官方 SDK 能提供更好的类型安全性和便利性。

```ruby

# Gemfile

gem "dodopayments"
```

运行 `bundle install` 以引入依赖。接下来，我们将设置一个 initializer 来配置客户端。我们会使用 Rails credentials 来保护 API 密钥。

```ruby

# config/initializers/dodo_payments.rb

require "dodopayments"

DODO_CLIENT = Dodopayments::Client.new(
  bearer_token: Rails.application.credentials.dig(:dodo, :api_key),
  environment: Rails.env.production? ? "live_mode" : "test_mode"
)
```

### 2. 创建产品

在接受付款之前，你需要在 Dodo Payments 控制台中定义产品。你可以选择一次性付款或各种 [订阅定价模式](https://dodopayments.com/blogs/subscription-pricing-models)。创建后，你会获得一个 `product_id`（例如 `pdt_123`）。

### 3. 结账流程

在 Rails 中，我们希望保持控制器精简。我们将创建一个简单的 `CheckoutsController`，用于处理支付会话的创建。

```ruby

# app/controllers/checkouts_controller.rb

class CheckoutsController < ApplicationController
  before_action :authenticate_user!

  def create
    # We create a checkout session for a specific product
    session = DODO_CLIENT.checkout_sessions.create(
      product_cart: [
        { product_id: params[:product_id], quantity: 1 }
      ],
      customer: {
        email: current_user.email,
        name: current_user.full_name
      },
      return_url: root_url,
      payment_link: true
    )

    # Redirect the user to the hosted checkout page
    redirect_to session.checkout_url, allow_other_host: true
  rescue Dodopayments::Errors::APIError => e
    flash[:error] = "Something went wrong: #{e.message}"
    redirect_back fallback_location: root_path
  end
end
```

现在，你可以在视图中添加一个简单的"立即购买"按钮：

```erb
<%# app/views/plans/index.html.erb %>
<div class="plan-card">
  <h3>Pro Plan</h3>
  <p>$29/month</p>
  <%= button_to "Subscribe Now", checkouts_path(product_id: "pdt_pro_plan"), method: :post, class: "btn-primary" %>
</div>
```

### 4. 处理 Webhook

Webhook 是任何支付集成中最关键的部分。它们可以确保你的应用与支付状态保持同步，即使用户在结账过程中关闭了浏览器。

我们将创建一个专用控制器，用于处理来自 Dodo Payments 的传入事件。

```ruby

# app/controllers/webhooks_controller.rb

class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token

  def create
    payload = request.body.read
    sig_header = request.headers["X-Dodo-Signature"]

    begin
      # Verify the webhook signature to ensure it's actually from Dodo
      event = DODO_CLIENT.webhooks.construct_event(
        payload,
        sig_header,
        Rails.application.credentials.dig(:dodo, :webhook_secret)
      )
    rescue JSON::ParserError, Dodopayments::Errors::SignatureVerificationError
      return head :bad_request
    end

    # Process the event asynchronously to avoid blocking the webhook response
    ProcessWebhookJob.perform_later(event.to_h)

    head :ok
  end
end
```

### 5. 使用 ActiveJob 异步处理

处理支付事件可能涉及数据库写入、发送电子邮件或调用外部 API。在 Rails 中，最佳实践是将这些工作交给后台任务处理。

```ruby

# app/jobs/process_webhook_job.rb

class ProcessWebhookJob < ApplicationJob
  queue_as :default

  def perform(event_data)
    case event_data[:type]
    when "subscription.active"
      handle_subscription_active(event_data[:data])
    when "subscription.cancelled"
      handle_subscription_cancelled(event_data[:data])
    when "payment.succeeded"
      handle_payment_succeeded(event_data[:data])
    end
  end

  private

  def handle_subscription_created(subscription)
    user = User.find_by(email: subscription[:customer][:email])
    return unless user

    user.update!(
      subscription_id: subscription[:id],
      plan_id: subscription[:product_id],
      status: :active
    )
  end

  def handle_subscription_cancelled(subscription)
    user = User.find_by(subscription_id: subscription[:id])
    user&.update!(status: :cancelled)
  end
end
```

### 6. 使用 Concern 管理访问权限

为了保持 `User` 模型整洁，你可以使用 Rails Concern 来处理订阅相关逻辑。这样就能轻松检查用户是否有权访问特定功能。

```ruby

# app/models/concerns/subscribable.rb

module Subscribable
  extend ActiveSupport::Concern

  included do
    enum :status, { inactive: 0, active: 1, cancelled: 2, past_due: 3 }
  end

  def subscribed?
    active? || past_due?
  end

  def pro?
    subscribed? && plan_id == "pdt_pro_plan"
  end
end

# app/models/user.rb

class User < ApplicationRecord
  include Subscribable
end
```

现在，在控制器或视图中检查访问权限就很简单了：

```ruby
def show
  @project = Project.find(params[:id])
  unless current_user.pro?
    redirect_to plans_path, alert: "Please upgrade to Pro to access this feature."
  end
end
```

### 8. 全球支付方式与转化率

从 Stripe 转向其他方案的最大优势之一，是原生支持全球支付方式。虽然 Stripe 支持许多支付方式，但 Dodo Payments 这样的 MoR（名义商户）通常可以开箱即用地提供更本地化的体验。

对于面向全球受众的 Rails 应用来说，只接受信用卡很容易导致高流失率。在世界许多地区，信用卡并不是人们购买软件的主要支付方式：

- **欧洲**：iDEAL（荷兰）、Bancontact（比利时）和 SEPA Direct Debit 都至关重要。
- **巴西**：Pix 已成为主流支付方式。
- **印度**：UPI 是数字交易的标准方式。

使用 Dodo Payments 时，系统会根据客户所在地自动启用这些支付方式。你的 Rails 应用无需添加任何额外逻辑，就能同时处理 Pix 交易和 Visa 卡付款。Webhook 负载保持一致，而 MoR（名义商户）会处理每种支付方式特有的结算逻辑。

### 9. 收入追回与催收

付款失败是运营 SaaS 时不可避免的一部分。卡片可能过期，银行可能出于风险防控原因拒绝交易，或者用户可能只是余额不足。

在传统网关设置中，你必须自行构建"催收"逻辑：

1. 通过 webhook 检测付款失败。
2. 向用户发送自动邮件。
3. 安排 3 天后重试。
4. 如果再次失败，再发送一封邮件。
5. 最终取消订阅并更新数据库。

Dodo Payments 会为你处理整个生命周期。他们负责重试逻辑和客户沟通。你的 Rails 应用只需监听最终的 `subscription.cancelled` 或 `subscription.on_hold` 事件，然后限制访问权限即可。这种"设置后无需操心"的收入追回方式，可以为你节省数十小时的开发时间，并追回价值数千美元的收入。

## 从 Stripe 迁移的详细策略

如果你已经在使用 Stripe，想到要迁移可能会让人望而生畏。不过，实际过程比看起来简单。以下是成功迁移的检查清单：

1. **审查当前计划**：将 Stripe Price ID 映射到 Dodo Product ID。确保计费周期（月付、年付）完全一致。
2. **导出客户数据**：使用 Stripe 的导出工具获取当前订阅用户列表。
3. **设置并行 Webhook**：在构建 Dodo 集成期间，保持 Stripe webhook 活跃。迁移期间，你的 Rails 应用可以同时处理两家服务商的事件。
4. **"先处理新注册用户"策略**：首先将所有新注册用户引导至 Dodo Payments。这样，你可以先在真实用户和生产环境中测试集成，再迁移现有用户。
5. **迁移现有订阅**：对于现有用户，你可以等到下一个计费周期再迁移，也可以使用迁移脚本在 Dodo 中创建对应订阅。
6. **停用 Stripe**：所有用户迁移完成，且 Stripe 上不再预计有周期性扣款后，你就可以安全地停用 Stripe 集成。

## 使用许可证密钥销售软件

许多 Rails 应用不只是 SaaS；它们还销售需要许可证密钥的可下载软件或插件。Dodo Payments 原生支持 [许可证密钥](https://docs.dodopayments.com/features/license-keys)，这对 Rails 开发者来说是一次重大升级。

你不必构建 `LicenseKey` 模型和生成算法，而是可以交给 Dodo 处理。当用户购买你的软件时，Dodo 会生成密钥，并将其包含在 webhook 负载中。你的 Rails 应用只需将其存储起来：

```ruby
def handle_payment_succeeded(payment)
  user = User.find_by(email: payment[:customer][:email])
  if payment[:license_key]
    user.update!(license_key: payment[:license_key])
    LicenseMailer.send_key(user).deliver_later
  end
end
```

随后，你可以在应用内部使用 Dodo API [验证许可证密钥](https://docs.dodopayments.com/api-reference/licenses/activate)，甚至可以通过 CLI 工具进行验证。

直接与 MoR（名义商户）集成，通常比与支付网关进行"抽象化"集成更简单。你可以用轻量级 SDK 和几个定义清晰的 webhook 处理器，替代一个依赖众多的复杂 gem。

## 顺利过渡的建议

- **使用测试模式**：Dodo Payments 提供完善的测试环境。你可以用它模拟成功付款、扣款失败和订阅取消。
- **幂等性**：确保 webhook 处理器具备幂等性。如果同一事件发送两次，你的应用应该能够优雅地处理，而不会创建重复记录。
- **日志记录**：记录所有传入的 webhook 负载。当付款似乎没有触发应用中预期的状态变化时，这些日志对于调试非常有价值。
- **迁移**：如果你正在从 Stripe 迁移，通常可以导出客户数据，并将其导入新的 MoR（名义商户）。查看 [如何在线销售软件](https://dodopayments.com/blogs/how-to-sell-software-online) 指南，了解管理迁移过程的建议。

## 结语：支付领域的约定优于配置

Rails 社区一直重视能够提升生产力的工具。我们选择 Postgres，而不是管理原始文件；我们选择 Sidekiq，而不是手动管理线程。选择 MoR（名义商户）也是同一类型的决策。

通过摆脱税务合规和计费基础设施中的手动工作，你正在拥抱 Rails 的真正精神。你选择了一种能够随业务扩展的 [SaaS 支付架构](https://dodopayments.com/blogs/payments-architecture-saas)，同时不会增加技术债务或法律债务。

无论你是在构建个人小项目还是全球企业，MoR（名义商户）的简洁性都能让你专注于真正重要的代码。到了 2026 年，最好的支付集成，就是那个不需要你亲自管理的集成。

准备好简化 Rails 计费了吗？了解 [Dodo Payments](https://dodopayments.com)，看看我们如何帮助你在无需承担税务负担的情况下[接受在线付款](https://dodopayments.com/blogs/how-to-accept-online-payments)。

## 常见问题

### Dodo Payments 会为我的 Rails 应用处理销售税吗？

会。作为 MoR（名义商户），Dodo Payments 会自动为每笔交易计算、收取并缴纳销售税、VAT 和 GST。你不需要在不同国家注册税务，也不需要为软件销售单独提交纳税申报表。

### 我可以将 Dodo Payments 与 Devise 等现有 Rails 身份验证 gem 一起使用吗？

当然可以。Dodo Payments 不依赖于你的身份验证系统。你只需将用户的电子邮件和姓名传递给支付会话，并在付款确认后使用 webhook 更新数据库中的用户状态。

### 如何处理订阅升级和降级？

你可以通过 Dodo Payments API 管理订阅变更，也可以将用户引导至托管计费门户。当计划发生变化时，系统会向你的 Rails 应用发送 webhook 事件，让你能够相应更新用户的 `plan_id` 和访问权限级别。

### Dodo Payments 提供 Ruby SDK 吗？

提供。官方 [Ruby SDK](https://docs.dodopayments.com/developer-resources/sdks/ruby) 可以让你轻松与 API 交互。它负责身份验证和请求重试，并提供用于创建支付会话和管理订阅的简洁接口。

### 支持哪些支付方式？

Dodo Payments 支持广泛的全球支付方式，包括信用卡、Apple Pay、Google Pay 以及各种本地支付选项。无论客户位于何处，这都能帮助你的 Rails 应用保持较高的转化率。
---
- [More Payments articles](https://dodopayments.com/blogs/category/payments)
- [All articles](https://dodopayments.com/blogs)