PAYATHON 2026

适用于 Rails 3 的最佳订阅计费系统是什么?

支付老李

结论

如果需要一款功能接近 Chargify 的托管式订阅计费平台,Recurly 通常是最直接的替代方案。它支持套餐、周期扣款、试用、优惠、账单和订阅生命周期管理,也提供 API,可与 Rails 应用集成。

其他选择包括:

  • Stripe Billing:API 清晰、生态成熟,适合希望自行控制业务流程的团队。
  • Braintree:同时支持支付和周期性计费,适用于需要 PayPal 等支付方式的场景。
  • Zuora:功能全面,但实施难度和成本通常更适合计费需求复杂的企业。
  • Active Merchant:这是 Rails 的支付网关抽象库,并非完整的订阅计费平台。套餐、续费和催收逻辑通常需要自行实现。

Rails 3 及其常用 Ruby 版本早已停止维护,当前支付 SDK 不一定能安装在旧项目中。选型时,应先确认供应商是否仍提供兼容项目 Ruby 版本的 SDK。如果无法兼容,可以直接调用 HTTPS API,或者将计费功能拆分到使用受支持运行环境的新服务中。

如何选择

除了是否支持订阅,还要确认以下能力:

  1. 套餐升级和降级能否按比例计费。
  2. 是否支持试用期、优惠券、税费和多币种。
  3. 扣款失败后能否自动重试并进入催收流程。
  4. Webhook 是否提供完善的签名验证。
  5. 是否允许导出客户、订阅和交易数据,以免被供应商锁定。
  6. API 是否支持幂等请求,避免网络重试造成重复订阅或重复扣款。
  7. 是否满足业务所在地区对税务、发票和数据合规的要求。

如果需求与 Chargify 基本一致,可以先验证 Recurly。如果更看重开发体验和灵活性,可以优先验证 Stripe Billing。

Rails 3 中的集成方式

可以将供应商 API 封装在独立的 gateway 中,避免控制器或业务模型直接依赖某个 SDK。以后更换计费平台时,只需替换适配器。

# app/services/billing_gateway.rb
class BillingGateway
  def initialize(client)
    @client = client
  end

  def create_customer(attributes)
    @client.create_customer(attributes)
  end

  def create_subscription(customer_id, plan_id)
    @client.create_subscription(
      :customer_id => customer_id,
      :plan_id => plan_id
    )
  end

  def cancel_subscription(subscription_id)
    @client.cancel_subscription(subscription_id)
  end
end

这里的 client 是项目为 Recurly、Stripe 或 Braintree 编写的适配器。各供应商的实际方法名和参数结构并不相同,具体实现应以所选平台的 API 文档为准。

控制器只负责接收请求并调用业务服务:

class SubscriptionsController < ApplicationController
  def create
    gateway = BillingGateway.new(configured_billing_client)

    subscription = gateway.create_subscription(
      current_user.billing_customer_id,
      params[:plan_id]
    )

    current_user.update_attributes(
      :billing_subscription_id => subscription.id,
      :subscription_status => subscription.status
    )

    redirect_to account_path, :notice => "订阅已创建"
  rescue BillingError => error
    Rails.logger.error(error.message)
    redirect_to plans_path, :alert => "暂时无法创建订阅,请稍后重试"
  end
end

configured_billing_client 和 BillingError 是应用自身的抽象,并非某家供应商的固定 API。适配器需要将不同供应商的异常统一转换为应用能够处理的错误。

使用 Webhook 同步状态

不能仅凭用户从支付页面跳转回来,就认定订阅已经成功。支付失败、退款、取消和续费等状态通常通过 Webhook 异步通知。

class BillingWebhooksController < ApplicationController
  skip_before_filter :verify_authenticity_token

  def create
    payload = request.raw_post
    signature = request.headers["HTTP_X_BILLING_SIGNATURE"]

    event = billing_webhook_verifier.verify(payload, signature)

    case event.type
    when "subscription.activated"
      update_subscription(event, "active")
    when "subscription.canceled"
      update_subscription(event, "canceled")
    when "payment.failed"
      update_subscription(event, "past_due")
    end

    head :ok
  rescue InvalidWebhookSignature
    head :unauthorized
  end

  private

  def update_subscription(event, status)
    user = User.find_by_billing_subscription_id(event.subscription_id)
    user.update_attributes(:subscription_status => status) if user
  end
end

示例中的事件名称和签名请求头只用于说明适配器的设计,不能直接视为某个供应商的真实字段。实现时必须按照平台要求处理签名算法、事件类型和重放防护。

重要注意事项

  • 不要在 Rails 数据库中保存完整银行卡号、CVC 等敏感信息。应使用供应商提供的托管支付页面或前端令牌化方案。
  • Webhook 可能重复发送,也可能乱序到达。需要保存供应商的事件 ID,并确保事件处理具有幂等性。
  • 本地订阅状态只是缓存。发生争议时,应通过 API 查询供应商侧的最终状态。
  • 创建客户和订阅时需要记录远端 ID,但不要将业务权限永久绑定到某个供应商特有的状态名称。
  • Rails 3 项目可能受到旧 TLS、Ruby/OpenSSL 和根证书的限制。即使 API 设计符合需求,也要在测试环境中验证 HTTPS 连接。
  • 不要为了安装现代支付 SDK 而盲目升级单个 gem,因为它可能要求更高版本的 Ruby 或 Rails。如果旧运行环境无法安全支持当前 API,拆分独立的计费服务通常比继续固定旧 SDK 更稳妥。

综合比较,Recurly 与 Chargify 最为接近,而 Stripe Billing 的 API 和扩展性通常更有吸引力。最终选型前,可以做一个小型验证项目,依次测试创建客户、开始订阅、变更套餐、模拟扣款失败、取消订阅,并完整处理 Webhook。

备注:内容仅供参考。