Siamak Kosari
Siamak Kosari

Reputation: 11

Stripe/Rails: "No such token: undefined"

I have been trying to get Stripe to return a token to my rails app but I keep getting this error:

Stripe::InvalidRequestError in Users::RegistrationsController#create No such token: undefined

Chrome highlights this line:

customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)

I have also tried changing "card" to "source" and still it comes back as token undefined:

{"utf8"=>"✓",
 "authenticity_token"=>"returns a token :)",
 "plan"=>"2",
 "user"=>{"email"=>"sljkdfhgvbdlvb@ae;klfgjbearfgvkujb.com",
 "password"=>"[FILTERED]",
 "password_confirmation"=>"[FILTERED]",
 "stripe_card_token"=>"undefined"}}

I also get a 'block in create' & 'create' in the application trace

app/models/user.rb:11:in save_with_payment' app/controllers/users/registrations_controller.rb:8:inblock in create' app/controllers/users/registrations_controller.rb:4:in `create'

registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController  #given to us by Devise
    #creating a class Users and inheriting devise
    def create  #When the user submits their form
       super do |resource| #importing to create action code that is inside the devise gem
          if params[:plan] #when user submits basic or pro form
              resource.plan_id = params[:plan] #were going to cath that form and see if param :plan was submitted and if yes then we save to resource.plan_id
              if resource.plan_id == 2 # if User.first_plan.id = 2
                  resource.save_with_payment # if id does = 2 then we save_with_payment defined in models/user.rb otherwise
              else  #if id = 1
                  resource.save #just do a regular save to resources
              end
          end
       end
    end

end

I tried restarting the server I tried a bundle update Here are some posts I've read:

Stripe Integration - Dynamically adding attr value in to the hidden_field

https://github.com/tyler-johnson/stripe-meteor/issues/25

I've also tried 4 different card #'s according to

https://stripe.com/docs/testing

Any help would be greatly appreciated :)

FOR REFERENCE:

application.yml

stripe_api_key: test key
stripe_publishable_key: pk test key
#
production:
  stripe_api_key: test key
  stripe_publishable_key: pk test key

users.js

/* global $ */
$(document).ready(function() {      //The .ready just means that the document will get loaded before teh JS runs
    Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));    //Lets grab generic meta tag contents. We can use it because we loaded the JS Stripe file
    // Watch for a form submission:
    $("#form-submit-btn").click(function(event) {  //When the user clicks on submit, we add an event listener to "next line"
        event.preventDefault();  //Dont send anything to the server just yet
        $('input[type=submit]').prop('disabled', true);  //This disables the button
        var error = false;  //establishing a variable false
        var ccNum = $('#card-number').val(),  //storing variables
            cvcNum = $('#card_code').val(),
            expMonth = $('#card_month').val(),
            expYear = $('#card_year').val();

        if (!error) {   //if there are no errors
            //Get the Stripe token:
            Stripe.createToken({ //Ship off the data entered to STRIPE
                number: ccNum,
                cvc: cvcNum,
                exp_month: expMonth,
                exp_year: expYear
            }, stripeResponseHandler);  //Once stripe returns TOKEN
        }
        return false;
    }); //form submission

    function stripeResponseHandler(status, response) {  //response coming back from server
        //Get a reference to the form:
        var f = $("#new_user"); //Lets use this form we made

        //Get the token from the response:
        var token = response.id;  //coming from response above and gives us card TOKEN

        //Add the token to the form:
        f.append('<input type="hidden" name="user[stripe_card_token]" value="' + token + '" />'); //and append the value for the field

        //Submit the form:
        f.get(0).submit(); //f.get(0) means we only want to the first forn incase there are multiple forms returned and submit
    }
});

user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  belongs_to :plan
  attr_accessor :stripe_card_token #stripe_card_token hidden field value

  def save_with_payment #method used in /app/controllers/users/registrations_controller.rb
    if valid? #If user filled out form properly
      customer = Stripe::Customer.create(description: email, plan: plan_id, source: stripe_card_token)
      self.stripe_customer_token = customer.id #setting property of user to user id returned from stripe
      save! #saving entire user object to database by creating new migration file
    end
  end
end

stripe.rb

Stripe.api_key = ENV["stripe_api_key"]
STRIPE_PUBLIC_KEY = ENV["stripe_publishable_key"] #The ENV comes from the figaro file

migration file (rails generated)

class AddStripeCustomerTokenToUsers < ActiveRecord::Migration
  def change
      add_column :users, :stripe_customer_token, :string 
  end #add a column to the user database and call it stripe ciutomer token as a string
end #bundle exec rake db:migrate after you created this

application.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>DevMatch</title>
  <%= stylesheet_link_tag    'application', media: 'all' %>
  <%= javascript_include_tag "https://js.stripe.com/v2/", type: 'text/javascript' %>
  <%= javascript_include_tag 'application'%>
  <%= tag :meta, :name => "stripe-key", :content => STRIPE_PUBLIC_KEY %>
  <%= csrf_meta_tags %>
</head>
<body>
  <nav class="navbar navbar-inverse navbar-static-top" role="navigation">
    <div class='container'>
      <div class='navbar-header'>
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main-nav-collapse">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <%= link_to root_path, class: 'navbar-brand' do %>
          <i class="fa fa-users"></i>
          DevMatch
        <% end %>
      </div>
      <div class="collapse navbar-collapse" id="main-nav-collapse">
        <div class="navbar-nav navbar-right">
          <% if current_user %>
            <%= button_to "Sign Out", destroy_user_session_path, method: :delete, class: 'btn btn-primary navbar-btn' %>
          <% else %>
            <%= link_to "Log In", new_user_session_path, class: 'btn btn-primary navbar-btn', method: :get %>
        </div>
        <ul class="nav navbar-nav navbar-right">
          <li><%= link_to "About", about_path %></li>
          <li><%= link_to "New Contact", new_contact_path %></li>
        </ul>
      </div><!-- /.navbar-collapse -->
    </div>
  </nav>

<div class="container">
  <% flash.each do |key, value| %>
    <%= content_tag :div, value, class: "alert alert-#{key}" %>
  <% end %>

  <%= yield %>
  <% end %>
</div>

</body>

</html>

Upvotes: 1

Views: 872

Answers (2)

Beulah Akindele
Beulah Akindele

Reputation: 649

Your error is probably caused by an invalid card number.

Comment out your f.get(0).submit and use

console.log(`status: ${status}, response: ${response}`);

At the beginning of stripeResponseHandler function to get the actual error being sent from Stripe. An error code will be returned in status.

Just lookup stripe error YOUR_ERROR_CODE and you'll find a solution. A pretty common one is 402, which means your card number is invalid. Here is a list of some stripe errors.

Upvotes: 0

gwydion93
gwydion93

Reputation: 1923

It appears that we were working on a similar project because I had this same issue using the method you are using. After trying the same fixes that you did (and still getting the same error), I finally discovered a small error in the directions that we both may have used to set up Stripe. The first clue is to look at the variable values in your users.js file. I noticed a typo right off the bat in yours. You have

var ccNum = $('#card-number').val(),  //storing variables
        cvcNum = $('#card_code').val(),
        expMonth = $('#card_month').val(),
        expYear = $('#card_year').val();

Notice that you have #card-number when it should be #card_number (with an _ not a -). While you don't have it listed, you also need to check the _pro_form.html.erb file, or it's equivalent. In my case, I had

 <%= label_tag :card_code, "Credit Card Number" %>

when it should have been

 <%= label_tag :card_number, "Credit Card Number" %>

Make sure, that those values in the _pro_form.html.erb (or equivalent) file are matching to those in the users.js file. Hope that helps.

Upvotes: 1

Related Questions