nil:NilClass 的 NoMethodError 未定义方法“id”:

NoMethodError undefined method `id' for nil:NilClass:

我知道这类问题已经回答了多次,但我真的无法弄清楚是什么导致了这里的问题,我在解决这个问题时遇到了麻烦。当我尝试创建新注册 ( http://localhost:3000/registrations/new?course_id=1 ) 时,我总是遇到同样的错误:

NoMethodError at /registrations

undefined method `id' for nil:NilClass

这是我的 RegistrationsController:

class RegistrationsController < ApplicationController
  before_action :set_registration, only: [:show, :edit, :update, :destroy]

  def index
    @registrations = Registration.all
  end

  def show
  end

  def new
    @registration = Registration.new
    @course = Course.new
    @course = Course.find_by id: params["course_id"]
  end

  def create
    @registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
    raise "Please Check Registration Errors" unless @registration.valid?
    @registration.process_payment
    @registration.save
    redirect_to @registration, notice: 'Registration was successfully created.'
  rescue Exception => e
    flash[:error] = e.message
    render :new
  end

  protect_from_forgery except: :webhook
  def webhook
    event = Stripe::Event.retrieve(params["id"])

    case event.type
      when "invoice.payment_succeeded" #renew subscription
        Registration.find_by_customer_id(event.data.object.customer).renew
    end
    render status: :ok, json: "success"
  end

  private

    def stripe_params
      params.permit :stripeEmail, :stripeToken
    end

    def set_registration
      @registration = Registration.find(params[:id])
    end

    def registration_params
      params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token)
    end

end

我的注册模型:

class Registration < ActiveRecord::Base
  belongs_to :course

  def process_payment
    customer_data = {email: email, card: card_token}.merge((course.plan.blank?)? {}: {plan: course.plan})
    customer = Stripe::Customer.create customer_data

      Stripe::Charge.create customer: customer.id,
                            amount: course.price * 100,
                            description: course.name,
                            currency: 'usd'
      #Annotate Customer Id when Registration is Created
      cusotmer_id = customer.id

  end

  def renew
    update_attibute :end_date, Date.today + 1.month
  end

end

注册New.html.haml文件:

%section#course-content
  %section#ruby
    %section.detailed-syllabus
      .wrapper-inside
        = form_for @registration, html: { class: "basic-grey" } do |f|
          - if @registration.errors.any?
            #error_explanation
              %h2
                = pluralize(@registration.errors.count, "error")
                prohibited this registration from being saved:
              %ul
                - @registration.errors.full_messages.each do |message|
                  %li= message
          .field
            = f.hidden_field :course_id, value: @course.id
          .field
            = f.label :full_name
            = f.text_field :full_name
          .field
            = f.label :company
            = f.text_field :company
          .field
            = f.label :email
            = f.text_field :email
          .field
            = f.label :telephone
            = f.text_field :telephone

            //‘Stripe.js’ will recognize the card data because we have marked the inputs with ‘data-stripe’ attribute as: number, cvv, exp-month and exp-year.
            = javascript_include_tag "https://js.stripe.com/v2/"
            :javascript
              Stripe.setPublishableKey('#{Rails.application.secrets.stripe_publishable_key}');

            = label_tag "Card Number", nil, required: true
            .control-group
              .controls
                = text_field_tag :card_number, nil, class: "input-block-level", "data-stripe" => "number"

            = label_tag "Card Verification", nil, required: true
            .control-group
              .controls
                = text_field_tag :card_verification, nil, class: "input-block-level", "data-stripe" => "cvv"

            = label_tag "Card Expires", nil, required: true
            = select_tag :exp_month, options_for_select(Date::MONTHNAMES.compact.each_with_index.map { |name,i| ["#{i+1} - #{name}", i+1] }), include_blank: false, "data-stripe" => "exp-month", class: "span2"
            = select_tag :exp_year, options_for_select((Date.today.year..(Date.today.year+10)).to_a), include_blank: false, "data-stripe" => "exp-year", class: "span1"


          .actions
          = f.submit "Registration Payment", class: "btn", style: "color: white;background: rgb(242, 118, 73);"

有人知道如何帮助我吗?非常感谢所有帮助。 任何人都可以指导我如何在 2 个模型之间传递 id,就像这个人在 2 个模型之间所做的那样,因为他正在为一个模型创建脚手架,但传递 ID 也可以让他为另一个模型创建值,而无需为另一个控制器创建操作 https://github.com/gotealeaf/stripe-basics.git

已编辑: GitHub 此代码的存储库 https://github.com/ChiragArya/Stripe_CheckOut_Demo

尝试将注册#new 操作更改为

def new

  @course = Course.find(params[:course_id])
  @registration = @course.registrations.new

end

将此添加到您的 def create

def create
    @course = Course.find_by id: params["registration"]["course_id"]
    @registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
    raise "Please Check Registration Errors" unless @registration.valid?
    @registration.process_payment
    @registration.save
    redirect_to @registration, notice: 'Registration was successfully created.'
  rescue Exception => e
    flash[:error] = e.message
    @course = Course.find_by id: params["registration"]["course_id"]
    render :new
end

根据您的评论,错误似乎是由以下原因引起的:

@course.id being nil

解决此问题的方法是确保正确定义 @course。您需要执行以下操作:

def new
   @registration = Registration.new
   @course = Course.find_by id: params["course_id"]
end

你在这里遇到的另一个问题是你的路线应该能够处理 courses 而不必附加 ?course_id=1:

#config/routes.rb
resources :registrations do
   get :course_id, to: "registrations#new" #-> yoururl.com/registrations/:course_id
end

这仍然会在 new 操作中为您提供 course_id 参数;只是让它更 Rails.

--

控制器

您的代码还需要一些结构(您的目标是 fat model, thin controller)。看来您是作为 Ruby 开发人员来到 Rails;您需要了解 Rails 为您处理了大部分异常等。

具体来说,您需要了解如何从操作中删除代码:

 def create
    @registration = Registration.new registration_params
    @registration.process_payment
    if @registration.save
        redirect_to @registration, notice: 'Registration was successfully created.'
    else
        # handle error here
    end
  end

  private

  def registration_params
      params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token).merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
  end

-

`id' for nil:NilClass

最后,你必须记住这个错误基本上意味着你试图为其调用操作的变量是 nil

Ruby 用 NilClass 对象填充 nil 变量,因此很难确定错误到底是什么。这意味着您尝试在 上调用方法的变量没有 具有上述方法,因为 Ruby 已经用 NilClass 填充了它对象。