#<Stripe::Customer:0x00007f1ac4d0b548> 的未定义方法“订阅”/无法为 SubscriptionsController 找到操作 'index'

Undefined method `subscriptions' for #<Stripe::Customer:0x00007f1ac4d0b548> / The action 'index' could not be found for SubscriptionsController

在我使用 Stripe API 提交卡详细信息后,我将 运行 留在这两个错误中,然后该应用程序应创建一个新订阅者并将其重定向到图书馆,但我却得到了:

Undefined method `subscriptions' for #Stripe::Customer:0x00007f1ac4d0b548

The action 'index' could not be found for SubscriptionsController

而且我总是先遇到第一个错误,然后当我刷新页面时它会变成第二个错误。

这是我的 subscriptions_controller (/app/controllers/subscriptions_controller.rb):

    class SubscriptionsController < ApplicationController
    layout "subscribe"
    before_action :authenticate_user!, except: [:new, :create]

    def new
      if user_signed_in? && current_user.subscribed?
        redirect_to root_path, notice: "You are already a subscriber!"
      end
    end

    def create
      Stripe.api_key = Rails.application.credentials.stripe_api_key

      plan_id = params[:plan_id]
      plan = Stripe::Plan.retrieve(plan_id)
      token = params[:stripeToken]

      customer = if current_user.stripe_id?
                   Stripe::Customer.retrieve(current_user.stripe_id)
                 else
                   Stripe::Customer.create(email: current_user.email, source: token)
                 end

      subscription = customer.subscriptions.create(plan: plan.id)

      options = {
        stripe_id: customer.id,
        stripe_subscription_id: subscription.id,
        subscribed: true,
      }

      options.merge!(
        card_last4: params[:user][:card_last4],
        card_exp_month: params[:user][:card_exp_month],
        card_exp_year: params[:user][:card_exp_year],
        card_type: params[:user][:card_type]
      ) if params[:user][:card_last4]

      current_user.update(options)

      redirect_to root_path, notice: "Your subscription was set up successfully!"
    end

    def destroy
      customer = Stripe::Customer.retrieve(current_user.stripe_id)
      customer.subscriptions.retrieve(current_user.stripe_subscription_id).delete
      current_user.update(stripe_subscription_id: nil)

      redirect_to root_path, notice: "Your subscription has been cancelled."
    end
end

这是我的 subscribe.html.erb (app/views/layouts/subscribe.html.erb)

<!DOCTYPE html>
<html>
  <head>
    <title><%= Rails.configuration.application_name %></title>
    <%= csrf_meta_tags %>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <%= stylesheet_link_tag 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'https://js.stripe.com/v3/','data-turbolinks-track': 'reload' %>
    <%= tag :meta, name: "stripe-key", content: Rails.application.credentials.stripe_publishable_key %>
  </head>

  <body class="<%= yield (:body_class) %>">
    <% if flash[:notice] %>
      <div class="notification is-success global-notification">
        <p class="notice"><%= notice %></p>
      </div>
    <% end %>

    <% if flash[:alert] %>
    <div class="notification is-danger global-notification">
      <p class="alert"><%= alert %></p>
    </div>
    <% end %>

     <nav class="navbar is-dark" role="navigation" aria-label="main navigation">
      <div class="navbar-brand">
        <div class="navbar-item">
          <h1 class="title is-5 has-text-white"><%= Rails.configuration.application_name %></h1>
        </div>
      </div>
    </nav>

    <div class="container">
      <%= yield %>
    </div>

  </body>
</html>

这里是/app/views/subscriptions/new.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title><%= Rails.configuration.application_name %></title>
    <%= csrf_meta_tags %>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <%= stylesheet_link_tag 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'https://js.stripe.com/v3/','data-turbolinks-track': 'reload' %>
    <%= tag :meta, name: "stripe-key", content: Rails.application.credentials.stripe_publishable_key %>
  </head>

  <body class="<%= yield (:body_class) %>">
    <% if flash[:notice] %>
      <div class="notification is-success global-notification">
        <p class="notice"><%= notice %></p>
      </div>
    <% end %>

    <% if flash[:alert] %>
    <div class="notification is-danger global-notification">
      <p class="alert"><%= alert %></p>
    </div>
    <% end %>

     <nav class="navbar is-dark" role="navigation" aria-label="main navigation">
      <div class="navbar-brand">
        <div class="navbar-item">
          <h1 class="title is-5 has-text-white"><%= Rails.configuration.application_name %></h1>
        </div>
      </div>
    </nav>

    <div class="container">
      <%= yield %>
    </div>

  </body>
</html>

这是用于订阅的 javascript 文件 (app/assets/javascripts/subscriptions.js)

document.addEventListener("turbolinks:load", function() {
  const publishableKey = document.querySelector("meta[name='stripe-key']").content;
  const stripe = Stripe(publishableKey);

  const elements = stripe.elements({
    fonts: [{
      cssSrc: "https://rsms.me/inter/inter-ui.css"
    }],
    locale: "auto"
  });

  const style = {
    base: {
      color: "#32325d",
      fontWeight: 500,
      fontFamily: "Inter UI, Open Sans, Segoe UI, sans-serif",
      fontSize: "16px",
      fontSmoothing: "antialiased",

      "::placeholder": {
        color: "#CFD7DF"
      }
    },
    invalid: {
      color: "#E25950"
    }
  };

  const card = elements.create('card', { style });

  card.mount("#card-element");

  card.addEventListener('change', ( {error} ) => {
    const displayError = document.getElementById('card-errors');
    if(error) {
      displayError.textContent = error.message;
    } else {
      displayError.textContent = "";
    }
  });

  const form = document.getElementById('payment-form');

  form.addEventListener('submit', async(event) => {
    event.preventDefault();

    const { token, error } = await stripe.createToken(card);

    if (error) {
      const errorElement = document.getElementById('card-errors');
      errorElement.textContent = error.message;
    } else {
      stripeTokenHandler(token);
    }
  });


  const stripeTokenHandler = (token) => {
    const form = document.getElementById('payment-form');
    const hiddenInput = document.createElement('input');
    hiddenInput.setAttribute('type', 'hidden');
    hiddenInput.setAttribute('name', 'stripeToken');
    hiddenInput.setAttribute('value', token.id);
    form.appendChild(hiddenInput);

    ["type", "last4", "exp_month", "exp_year"].forEach(function(field) {
      addCardField(form, token, field);
    });

    form.submit();
  }

  function addCardField(form, token, field) {
    let hiddenInput = document.createElement('input');
    hiddenInput.setAttribute('type', 'hidden');
    hiddenInput.setAttribute('name', "user[card_" + field + "]");
    hiddenInput.setAttribute('value', token.card[field]);
    form.appendChild(hiddenInput);
  }

});

这是我的 routes.rb (/config/routes.rb):

require 'sidekiq/web'

Rails.application.routes.draw do
  resources :books do
    member do
      put "add", to: "books#library"
      put "remove", to: "books#library"
    end
  end
  resources :library, only:[:index]
  resources :pricing, only:[:index]
  devise_for :users, controllers: { registrations: "registrations" }
  root to: 'books#index'
  resources :subscriptions
end

这是显示索引错误时的控制台 console

任何想法都会很有帮助!谢谢你

有多种创建订阅的方法,如果我记得,那是一种较旧的方法,但现在您可以 - 并且应该 - 创建它 like this:

Stripe::Subscription.create({
  customer: customer.id,
  items: [
    {price: plan.id},
  ],
})