NoMethodError未定义方法`id'为零:NilClass:

时间:2015-09-23 07:30:48

标签: ruby-on-rails ruby ruby-on-rails-4 stripe-payments

我知道这种问题已经多次回答了,但是我真的无法弄清楚这里导致问题的原因,我在解决这个问题时遇到了麻烦。我在尝试创建新注册时遇到同样的错误(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);"

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

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

3 个答案:

答案 0 :(得分:1)

根据您的评论,出现错误的原因是:

  

@course.idnil

解决此问题的方法是确保正确定义@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

这仍然会在course_id操作中为您提供new参数;只是让它更多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'代表nil:NilClass

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

Ruby使用nil对象填充NilClass变量,因此很难确定错误实际是什么。所有这意味着你试图在上调用方法的变量没有上述方法,因为Ruby已经用NilClass对象填充它。

答案 1 :(得分:0)

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

def new

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

end

答案 2 :(得分:0)

GROUP BY ?class

中添加此内容
def create