Stripe 订阅和 Rails 4:当新用户尝试购买时,没有路由匹配 [POST]“/subscriptions”

Stripe subscriptions and Rails 4: No route matches [POST] "/subscriptions" when new user tries to buy

我正在向现有的 Rails 4 应用添加订阅购买,我们使用 Devise。这是遵循掌握现代支付方法。

我可以从我的 rails 控制台(ID 为 1)成功创建一个计划,并将其显示在 Stripe 中。所以我知道基本的握手是可以的。

作为用户,当我转到支付页面并填写所有信息并单击提交时,我收到错误消息:路由错误:没有路由匹配 [POST]“/subscriptions”。

我想购买的用户付费页面位于 localhost:3000/subscriptions/new?plan_id=1

看起来像这样: subscriptions/new.html.erb

<% unless @subscription.errors.blank? %>
    <%= @subscription.errors.full_messages.to_sentence %>
<% end %>

<h2>Subscribing to <%= @plan.name %></h2>

<%= form_for @subscription, html: { id: 'payment-form' } do |f| %>
    <input type="hidden" name="plan_id" value="<%= @plan.id %>" />
    <span class="payment-errors"></span>

    <div class="form-row">
      <label>
        <span>Email Address</span>
        <input type="email" size="20" name="email_address"/>
      </label>
    </div>

    <div class="form-row">
      <label>
        <span>Card Number</span>
        <input type="text" size="20" data-stripe="number"/>
      </label>
    </div>

    <div class="form-row">
      <label>
        <span>CVC</span>
        <input type="text" size="4" data-stripe="cvc"/>
      </label>
    </div>

    <div class="form-row">
      <label>
        <span>Expiration (MM/YYYY)</span>
        <input type="text" size="2" data-stripe="exp-month"/>
      </label>
      <span> / </span>
      <input type="text" size="4" data-stripe="exp-year"/>
    </div>

    <button type="submit">Pay Now</button>
<% end %>

我们有这些路线:

Helper  HTTP Verb   Path    Controller#Action
Path / Url      
Path Match
subscriptions_index_path    GET /subscriptions/index(.:format)  subscriptions#index
subscriptions_new_path  GET /subscriptions/new(.:format)    subscriptions#new
subscriptions_create_path   GET /subscriptions/create(.:format) subscriptions#create
subscriptions_show_path GET /subscriptions/show(.:format)   subscriptions#show
subscriptions_plans_path    GET /subscriptions/plans(.:format)  subscriptions#plans
subscriptions_update_path   GET /subscriptions/update(.:format) subscriptions#update
subscriptions_destroy_path  GET /subscriptions/destroy(.:format)    subscriptions#destroy
plans_index_path    GET /plans/index(.:format)  plans#index
plans_show_path GET /plans/show(.:format)   plans#show
stripe_checkout_path    POST    /stripe_checkout(.:format)  subscription#stripe_checkout
subscription_checkout_path  POST    /subscription_checkout(.:format)    subscription#subscription_checkout
new_user_session_path   GET /users/sign_in(.:format)    devise/sessions#new
user_session_path   POST    /users/sign_in(.:format)    devise/sessions#create
destroy_user_session_path   DELETE  /users/sign_out(.:format)   devise/sessions#destroy
user_password_path  POST    /users/password(.:format)   devise/passwords#create
new_user_password_path  GET /users/password/new(.:format)   devise/passwords#new
edit_user_password_path GET /users/password/edit(.:format)  devise/passwords#edit
PATCH   /users/password(.:format)   devise/passwords#update
PUT /users/password(.:format)   devise/passwords#update
cancel_user_registration_path   GET /users/cancel(.:format) users#cancel
user_registration_path  POST    /users(.:format)    users#create
new_user_registration_path  GET /users/sign_up(.:format)    users#new
edit_user_registration_path GET /users/edit(.:format)   users#edit
PATCH   /users(.:format)    users#update
PUT /users(.:format)    users#update
DELETE  /users(.:format)    users#destroy
accept_user_invitation_path GET /users/invitation/accept(.:format)  devise/invitations#edit
remove_user_invitation_path GET /users/invitation/remove(.:format)  devise/invitations#destroy
user_invitation_path    POST    /users/invitation(.:format) devise/invitations#create
new_user_invitation_path    GET /users/invitation/new(.:format) devise/invitations#new
PATCH   /users/invitation(.:format) devise/invitations#update
PUT /users/invitation(.:format) devise/invitations#update
users_path  GET /users(.:format)    users#index
POST    /users(.:format)    users#create
new_user_path   GET /users/new(.:format)    users#new
edit_user_path  GET /users/:id/edit(.:format)   users#edit
user_path   GET /users/:id(.:format)    users#show
PATCH   /users/:id(.:format)    users#update
PUT /users/:id(.:format)    users#update
DELETE  /users/:id(.:format)    users#destroy
entries_path    POST    /entries(.:format)  entries#create
new_entry_path  GET /entries/new(.:format)  entries#new
edit_entry_path GET /entries/:id/edit(.:format) entries#edit
entry_path  GET /entries/:id(.:format)  entries#show
PATCH   /entries/:id(.:format)  entries#update
PUT /entries/:id(.:format)  entries#update
DELETE  /entries/:id(.:format)  entries#destroy
orders_path GET /orders(.:format)   orders#index
POST    /orders(.:format)   orders#create
new_order_path  GET /orders/new(.:format)   orders#new
edit_order_path GET /orders/:id/edit(.:format)  orders#edit
order_path  GET /orders/:id(.:format)   orders#show
PATCH   /orders/:id(.:format)   orders#update
PUT /orders/:id(.:format)   orders#update
DELETE  /orders/:id(.:format)   orders#destroy
last24_s1_events_path   GET /s1_events/last24(.:format) s1_events#last24
s1_event_subscriptions_path GET /s1_events/:s1_event_id/subscriptions(.:format) subscriptions#index
POST    /s1_events/:s1_event_id/subscriptions(.:format) subscriptions#create
new_s1_event_subscription_path  GET /s1_events/:s1_event_id/subscriptions/new(.:format) subscriptions#new
s1_events_path  GET /s1_events(.:format)    s1_events#index
upmin_path      /admin  Upmin::Engine
root_path   GET /   dashboard#index
income_path GET /income(.:format)   dashboard#income
liquidity_path  GET /liquidity(.:format)    dashboard#liquidity
time_horizon_path   GET /time-horizon(.:format) dashboard#time_horizon
get_feed_path   GET /get-feed(.:format) pages#get_feed
get_updates_path    GET /get-updates(.:format)  pages#get_updates
subscriptions_path  GET /subscriptions(.:format)    pages#subscriptions
api_path    GET /api(.:format)  pages#api
icons_path  GET /icons(.:format)    pages#icons
contact_us_path GET /contact_us(.:format)   contacts#new
s1_qa_path  GET /s1-qa(.:format)    pages#s1_qa
contacts_path   POST    /contacts(.:format) contacts#create
Routes for Upmin::Engine
root_path   GET /   upmin/models#dashboard
upmin_dashboard_path    GET /   upmin/models#dashboard
upmin_search_path   GET|POST    /m/:klass(.:format) upmin/models#search
upmin_new_model_path    GET /m/:klass/new(.:format) upmin/models#new
upmin_create_model_path POST    /m/:klass/new(.:format) upmin/models#create
upmin_model_path    GET /m/:klass/i/:id(.:format)   upmin/models#show
PUT /m/:klass/i/:id(.:format)   upmin/models#update
upmin_action_path   POST    /m/:klass/i/:id/:method(.:format)   upmin/models#action

我们的 routes.rb 文件如下所示:

Rails.application.routes.draw do

  get 'subscriptions/index'

  get 'subscriptions/new'

  get 'subscriptions/create'

  get 'subscriptions/show'

  get 'subscriptions/plans'

  get 'subscriptions/update'

  get 'subscriptions/destroy'

  get 'plans/index'

  get 'plans/show'

  post 'stripe_checkout' => 'subscription#stripe_checkout'
  post 'subscription_checkout' => 'subscription#subscription_checkout'


  devise_for :users, :controllers => { registrations: 'users' }
  resources :users
  resources :entries, except: [:index]
  resources :orders
  resources :s1_events, only: [:index] do
    get 'last24', on: :collection
  resources :subscriptions, only: [:index, :new, :create]
  end

  mount Upmin::Engine => '/admin'

  root to: 'dashboard#index'
  get 'income', to: 'dashboard#income'
  get 'liquidity', to: 'dashboard#liquidity'
  get 'time-horizon', to: 'dashboard#time_horizon'
  get 'get-feed', to: 'pages#get_feed'
  get 'get-updates', to: 'pages#get_updates'
  get 'subscriptions', to: 'pages#subscriptions'
  get 'api', to: 'pages#api'
  get 'icons', to: 'pages#icons'
  get 'contact_us', to: 'contacts#new'
  get 's1-qa', to: 'pages#s1_qa'
  resources 'contacts', only: [:create]
end

我们有一个 CreateSubscription 服务对象: create_subscription.rb

class CreateSubscription
  def self.call(plan, email_address, token)
    user, raw_token = CreateUser.call(email_address)

    subscription = Subscription.new(
        plan: plan,
        user: user
    )

    begin
      stripe_sub = nil
      if user.stripe_customer_id.blank?
        customer = Stripe::Customer.create(
            source: token,
            email: user.email,
            plan: plan.stripe_id,
        )
        user.stripe_customer_id = customer.id
        user.save!
        stripe_sub = customer.subscriptions_choices.first
      else
        customer = Stripe::Customer.retrieve(user.stripe_customer_id)
        stripe_sub = customer.subscriptions_choices.create(
            plan: plan.stripe_id
        )
      end

      subscription.stripe_id = stripe_sub.id

      subscription.save!
    rescue Stripe::StripeError => e
      subscription.errors[:base] << e.message
    end

    subscription
  end
end

这里指的是一个CreateUser服务对象: create_user.rb

class CreateUser
  def self.call(email_address)

    user = User.find_by(email: email_address)

    return user if user.present?

    raw_token, enc_token = Devise.token_generator.generate(
        User, :reset_password_token)
    password = SecureRandom.hex(32)

    user = User.create!(
        email: email_address,
        password: password,
        password_confirmation: password,
        reset_password_token: enc_token,
        reset_password_sent_at: Time.now
    )

    return user, raw_token
  end
end

这些应该一起工作的方式是在 Devise 之后。意思是,如果用户已经存在,它会为此添加付款。如果没有,请创建一个新用户。所以这里的 Devise 应该没有任何问题。

非常感谢任何有关如何解决此错误并让我的用户购买订阅的建议。

错误消息非常简单明了。您没有 POST /subscriptions 路线。

你还有一堆其他东西,比如 get 'subscriptions/create'POST /s1_events/:s1_event_id/subscriptions

我建议您先清理路线。

不好

get 'subscriptions/index'
get 'subscriptions/new'
get 'subscriptions/create'
get 'subscriptions/show'
get 'subscriptions/plans'
get 'subscriptions/update'
get 'subscriptions/destroy'

永远不要这样做。 GET 操作应该始终是 idempotent。您还违反了 Rails REST 约定:

GET    '/subscriptions'     => index
POST   '/subscriptions'     => create
GET    '/subscriptions/:id' => show
PATCH  '/subscriptions/:id' => update
DELETE '/subscriptions/:id' => destroy

除非您GET subscriptions/update?id=foo&bar=baz,否则那些 subscriptions/update 和销毁路径将不起作用。呸

很好

resources :subscriptions

http://guides.rubyonrails.org/routing.html#resource-routing-the-rails-default