Codestudio
Codestudio

Reputation: 525

Stripe Payment: undefined method `price' for nil:NilClass

I have an application that I am testing stripe payments on. Right now, I am trying to configuring the charge so that it takes the price from another model (pin.price) and charges it correctly. So far, I am running into the following error message:

NoMethodError in ChargesController#create undefined method `price' for nil:NilClass

app/controllers/charges_controller.rb

class ChargesController < ApplicationController

    def create
      # Amount in cents
      @amount = (@pin.price * 100).floor

      customer = Stripe::Customer.create(
        :email => params[:stripeEmail],
        :card  => params[:stripeToken]
      )

      charge = Stripe::Charge.create(
        :customer    => customer.id,
        :amount      => @amount,
        :description => 'Rails Stripe customer',
        :currency    => 'usd'
      )

    rescue Stripe::CardError => e
      flash[:error] = e.message
      redirect_to charges_path
    end
end

app/controllers/pins_controller.rb

class PinsController < ApplicationController
  before_action :set_pin, only: [:show, :edit, :update, :destroy, :bid]
  before_action :correct_user, only: [:edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index, :show]

  .....

    def pin_params
      params.require(:pin).permit(:description, :price, :image, :manufacturer, :model)
    end
end

app/db/migrate

class AddPriceToPins < ActiveRecord::Migration
  def change
    add_column :pins, :price, :decimal
  end
end

I'm pretty sure the error is coming from "@amount = (@pin.price * 100).floor" but I am just not sure how to better express this amount so each pin's price isn't static but matches to its current inputted value in the database.

EDIT: Including form with link to stripe payment code here:

 <%= form_tag charges_path, id: 'chargesForm' do %>
              <script src="https://checkout.stripe.com/checkout.js"></script>
              <%= hidden_field_tag 'stripeToken' %>
              <%= hidden_field_tag 'stripeEmail' %>  
              <button id="btn-buy" type="button" class="btn btn-success btn-lg btn-block"><span class="glyphicon glyphicon-heart"></span>   I want this!</button>

              <script>
                  var handler = StripeCheckout.configure({
                    key: '<%= Rails.configuration.stripe[:publishable_key] %>',
                    token: function(token, arg) {
                      document.getElementById("stripeToken").value = token.id;
                      document.getElementById("stripeEmail").value = token.email;
                      document.getElementById("chargesForm").submit();
                    }
                  });
                   document.getElementById('btn-buy').addEventListener('click', function(e) {
                    handler.open({
                      name: '<%= @pin.manufacturer %>',
                      description: '<%= @pin.description %>',
                      amount: '<%= (@pin.price * 100).floor %>'
                  });
                  e.preventDefault();
                 })
              </script>
          <% end %>

Any thoughts?

Upvotes: 0

Views: 1297

Answers (1)

Harrison Lucas
Harrison Lucas

Reputation: 2961

The problem is that in your charges controller @pin isn't assigned to anything and therefore has a value of nil hence the error.

You therefore need to assign @pin to a value before you call price on it. In order to do that you need to figure out how you are going to get the pin from the DB or whether or not you create it.

One solution could be to pass in the id of the pin in the request path, e.g.

create_charge_path(pin_id: 123) 

EDIT: This doesn't have to be hardcoded to 123 it can be whatever pin you like, just depends on where it's being called from. E.g. if you are calling from another controller action that has already loaded a particular pin from the database you could do:

create_charge_path(pin_id: pin.id)

Then in your ChargesController

class ChargesController < ApplicationController

    def create
      @pin = Pin.find(params[:pin_id])
      # Amount in cents
      @amount = (@pin.price * 100).floor

      customer = Stripe::Customer.create(
        :email => params[:stripeEmail],
        :card  => params[:stripeToken]
      )

      charge = Stripe::Charge.create(
        :customer    => customer.id,
        :amount      => @amount,
        :description => 'Rails Stripe customer',
        :currency    => 'usd'
      )

    rescue Stripe::CardError => e
      flash[:error] = e.message
      redirect_to charges_path
    end
end

This will then assign @pin to a pin with a database ID of 123.

Upvotes: 1

Related Questions