首页 > 解决方案 > Stripe and Rails 5 - Stripe::InvalidRequestError: 没有这样的计划:starter

问题描述

我几乎完成了 Ryan Bigg 的 Multitenancy with Rails - 第 2 版书,并且发现自己在将我的应用程序与 Stripe 集成时陷入困境。特别是,我遇到了这个问题:

测试失败如下所示:

Failures:

1) Subscriptions can be cancelled
     Failure/Error: subscription = customer.subscriptions.create(plan: "starter")

 Stripe::InvalidRequestError:
   No such plan: starter
 # ./spec/features/accounts/subscriptions_spec.rb:20:in `block (2 levels) in <top (required)>'
 # ./spec/rails_helper.rb:40:in `block (3 levels) in <top (required)>'
 # ./spec/rails_helper.rb:39:in `block (2 levels) in <top (required)>'
 # ------------------
 # --- Caused by: ---
 # RestClient::BadRequest:
 #   400 Bad Request
 #   ./spec/features/accounts/subscriptions_spec.rb:20:in `block (2 levels) in <top (required)>'

Finished in 1.42 seconds (files took 5.1 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/features/accounts/subscriptions_spec.rb:30 # Subscriptions can be cancelled

我的测试代码如下所示:

require "rails_helper"
require "stripe_plan_fetcher"

describe StripePlanFetcher do
  let(:faux_plan) do
    double("plan",
              id: "starter",
              nickname: "Starter",
              amount: 995)
  end

  it "fetches and stores plans" do
    expect(Stripe::Plan).to receive(:all).and_return([faux_plan])
    expect(Plan).to receive(:create).with({
      stripe_id: "starter",
      name: "Starter",
      amount: 995
      })

      StripePlanFetcher.store_locally
  end

  it "checks and updates plans" do
    expect(Stripe::Plan).to receive(:all).and_return([faux_plan])
    expect(Plan).to receive(:find_by).
                                with(stripe_id: faux_plan.id).
                                and_return(plan = double)
    expect(plan).to receive(:update).with({
      name: "Starter",
      amount: 995
      })

    expect(Plan).to_not receive(:create)

    StripePlanFetcher.store_locally
  end
end

除了测试规范失败之外,当我访问 subdomain.lvh.me:3000 并完成注册用户 + 输入测试 cc 信息的过程时,Stripe 过程似乎正在工作 - 在一定程度上 - 但我是重定向到这个错误:

Stripe::InvalidRequestError in Accounts::PlansController#chosen
Received unknown parameter: source

customer = Stripe::Customer.retrieve(current_account.stripe_customer_id)
plan = Plan.find(params[:account][:plan_id])
subscription = customer.subscriptions.create(
  plan: plan.stripe_id,
  source: params[:token]
)

我的计划控制器代码如下所示:

class Accounts::PlansController < Accounts::BaseController
  skip_before_action :subscription_required!

  def choose
    @plans = Plan.order(:amount)
  end

  def chosen
    customer = Stripe::Customer.retrieve(current_account.stripe_customer_id)
    plan = Plan.find(params[:account][:plan_id])
    subscription = customer.subscriptions.create(
      plan: plan.stripe_id,
      source: params[:token]
    )

    current_account.plan = plan
    current_account.stripe_subscription_id = subscription.id
    current_account.stripe_subscription_status = "active"
    current_account.save
    flash[:notice] = "Your account has been created."
    redirect_to root_url(subdomain: current_account.subdomain)
  end

  def cancel
    customer = Stripe::Customer.retrieve(current_account.stripe_customer_id)
    subscription = customer.subscriptions.retrieve(current_account.stripe_subscription_id).delete
    if subscription.status == "canceled"
      current_account.update_column(:stripe_subscription_id, nil)
      flash[:notice] = "Your subscription to Twist has been cancelled."
      redirect_to root_url(subdomain: nil)
    end
  end
end

--- 更新 1 ---

架构计划:

create_table "plans", force: :cascade do |t|
    t.string   "name"
    t.integer  "amount"
    t.string   "stripe_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

架构帐户:

create_table "accounts", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at",             null: false
    t.datetime "updated_at",             null: false
    t.integer  "owner_id"
    t.string   "subdomain"
    t.string   "stripe_customer_id"
    t.integer  "plan_id"
    t.string   "stripe_subscription_id"
    t.index ["plan_id"], name: "index_accounts_on_plan_id", using: :btree
    t.index ["subdomain"], name: "index_accounts_on_subdomain", using: :btree
  end

条纹计划提取器

class StripePlanFetcher
  def self.store_locally
    Stripe::Plan.all.each do |plan|
      if local_plan = Plan.find_by(stripe_id: plan.id)
        local_plan.update(
          name: plan.nickname,
          amount: plan.amount
        )
      else
        Plan.create(
          name: plan.nickname,
          amount: plan.amount,
          stripe_id: plan.id
        )
      end
    end
  end
end

标签: ruby-on-railsstripe-payments

解决方案


问题是您正在尝试使用属性创建订阅plan = "starter",但“计划”不是订阅的属性,它是对计划记录的引用。大多数可能的订阅有一个名为的属性plan_id(在未来发布所有模式 - 在这种情况下,知道订阅的模式会有所帮助)

因此,在这种情况下,您可能需要声明plan如下内容:

@plan = Plan.find_by(name: 'starter')

customer.subscriptions.create(plan: @plan)


推荐阅读