Script-Kiddie
Script-Kiddie

Reputation: 69

NoMethodError undefined method `id' for nil:NilClass:

I know this kind of question is already answered multiple times but i seriously unable to figure it out what is causing a problem here, I am having trouble solving this problem. I keep getting the same error when i'm trying to create new registration ( http://localhost:3000/registrations/new?course_id=1 ) :

NoMethodError at /registrations

undefined method `id' for nil:NilClass

Here is my 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

My Registration Model:

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

Registration New.html.haml File :

%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);"

Does anyone know how to assist me in this? Greatly appreciate all the help. Additional Can anyone please guide me through how to pass id between 2 models like this guy did between 2 models as he's creating a scaffold for one model but passing ID lets him create values for another model too without creating actions for another controller https://github.com/gotealeaf/stripe-basics.git

Edited: GitHub Repository For This Code https://github.com/ChiragArya/Stripe_CheckOut_Demo

Upvotes: 0

Views: 11050

Answers (3)

Richard Peck
Richard Peck

Reputation: 76784

From your comments, it appears the error is caused by :

@course.id being nil

The way to fix this is to ensure @course is defined properly. You need to do the following:

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

The other issue you have here is that your routes should be able to handle courses without having to append them with ?course_id=1:

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

This will still give you the course_id param in the new action; just makes it more Rails.

--

Controller

You also need some structure in your code (you're aiming for fat model, thin controller). It looks like you're coming to Rails as a Ruby dev; you need to appreciate that Rails handles most of the exceptions etc for you.

Specifically, you need to look at how to remove code out of your actions:

 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

Finally, you have to remember this error basically means the variable you're trying to invoke an action for is nil.

Ruby populates nil variables with a NilClass object, thus it's difficult to determine what the error actually is. All it means is that the variable you're trying to call a method on doesn't have the aforementioned method, as Ruby has populated it with the NilClass object.

Upvotes: 1

akbarbin
akbarbin

Reputation: 5105

add this in your 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

Upvotes: 0

Florin Ionita
Florin Ionita

Reputation: 271

Try changing Registration#new action to

def new

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

end

Upvotes: 0

Related Questions