Stripe: error messages when creating a client and / or collecting - Ruby on Rails

I implement Stripe in a Rails application and get an Invalid Token error when loading an input form - I have not submitted client data yet. I mainly followed http://railscasts.com/episodes/288-billing-with-stripe . I made a few changes because it was somewhat incomplete.

books / show.html.erb is the page on which I link to the form:

<b>Title:</b> <%= @book.title %> </p> <b>Author:</b> <% authorid = @book.author %></p> <%= @book.id %> <%= link_to "Buy Now", new_purchase_path(:book_id => @book.id) %> 

purchase / new.html.erb is where the user fills in the information. When this loads, I get an Invalid Token error:

 <%= form_for @purchase do |f| %> <% if @purchase.errors.any? %> <%= pluralize(@purchase.errors.count, "error") %> prohibited this purchase from being saved. <% @purchase.errors.full_messages.each do |msg| %> <%= msg %> <% end %> <% end %> <%= f.hidden_field :stripe_card_token %> <% if @purchase.stripe_card_token.present? %> Credit card has been provided. <% else %> <%= label_tag :card_number, "Credit Card Number" %> <%= text_field_tag :card_number, nil, name: nil %><p> <%= label_tag :card_code, "Security Code on Card (CVV)" %> <%= text_field_tag :card_code, nil, name: nil %><p> <%= label_tag :card_month, "Card Expiration" %> <%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %> <%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %> <% end %> <div id="stripe_error"> <noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript> </div> <%= f.submit "Purchase" %> <% end %> 

purchase.js.coffee is almost the same as in the tutorial. I have added some warnings. The status according to my Stripe dashboard is 402. This is a POST / v1 / tokens and Body Response error:

 error: type: "card_error" message: "This card number looks invalid" param: "number" 

purchases.js.coffee:

 jQuery -> Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content')) purchase.setupForm() purchase = setupForm: -> $('#new_purchase').submit -> $('input[type=submit]').attr('disabled', true) if $('#card_number').length purchase.processCard() false else true processCard: -> card = number: $('#card_number').val() cvc: $('#card_code').val() expMonth: $('#card_month').val() expYear: $('#card_year').val() Stripe.createToken(card, purchase.handleStripeResponse) handleStripeResponse: (status, response) -> if status == 200 alert('This token can still be charged.') alert(response.id) $('#purchase_stripe_card_token').val(response.id) $('#new_purchase')[0].submit() else alert(response.error.message) alert('The token was invalid, or has been used.') $('#stripe_error').text(response.error.message) $('input[type=submit]').attr('disabled', false) 

I tried several versions of my purchase.rb model, for example, commenting on the Stripe :: Charge function, but still get a Token 402 error. However, creating the Client is successful (code 200).

 class Purchase < ActiveRecord::Base attr_accessible :stripe_customer_token, :author_id, :book_id attr_accessor :stripe_card_token belongs_to :book def save_with_payment if valid? customer = Stripe::Customer.create( :description => "customer email", :card => stripe_card_token ) self.stripe_customer_token = customer.id # charge = Stripe::Charge.create( - this code doesn't work either # :amount => 1000, # :currency => "usd", # :card => stripe_card_token, # :description => "book title" # ) save! end rescue Stripe::InvalidRequestError => e logger.error "Stripe error while creating customer: #{e.message}" errors.add :base, "There was a problem with your credit card." false end end 

The error I get if I uncomment the code Stripe :: Charge: Stripe :: CardError in PurchaseController # create You cannot charge a client that does not have an active card

And, the create method in my purchases_controller.rb

 def create @purchase = Purchase.new(params[:purchase]) if @purchase.save_with_payment redirect_to @purchase, :notice => "Thank you for purchasing this book!" else render :new end end 

Here is my new method in purchase_controller.rb:

def new

  book = Book.find(params[:book_id]) @purchase = book.purchases.build 

end

BUT, if I click the "Back" button after submitting the purchase (to return to the purchase page /new.html.erb), the SECOND "purchase" and the code for this POST token in my log 200 (pass) band will be entered into my database !!!

Here's the javascript compiled from coffeescript:

(function () {

buying var;

jQuery (function () {

Stripe.setPublishableKey ($ ('meta [name = "strip-key"]') atr ('content').);

return purchase.setupForm ();

});

buy = {

setupForm: function () {

  $('#new_purchase').submit(function() { return $('input[type=submit]').attr('disabled', true); }); if ($('#card_number').length) { purchase.processCard(); return false; } else { return true; } 

},

processCard: function () {

  var card; card = { number: $('#card_number').val(), cvc: $('#card_code').val(), expMonth: $('#card_month').val(), expYear: $('#card_year').val() }; return Stripe.createToken(card, purchase.handleStripeResponse); 

},

handleStripeResponse: function (status, response) {

  if (status === 200) { alert('This token can still be charged.'); alert(response.id); $('#purchase_stripe_card_token').val(response.id); return $('#new_purchase')[0].submit(); } else { alert(response.error.message); alert('The token was invalid, or has been used.'); $('#stripe_error').text(response.error.message); return $('input[type=submit]').attr('disabled', false); } 

}

};

}) call (this) ;.

+4
source share
2 answers

As mentioned in my comment above, the margins of your CoffeeScript are slightly polished (spaces are significant for CS). This is not a syntax error, so it still compiles, but the generated JS is not what you intend. Here is the indented code.

 purchase = setupForm: -> $('#new_purchase').submit -> $('input[type=submit]').attr('disabled', true) if $('#card_number').length purchase.processCard() false else true # ... 

In sent JS, conditional if ($('#card_number').length) exists outside the anonymous function associated with the send event. This leads to the fact that the condition is launched immediately after the page loads, and not when the form is submitted. Since there is nothing in the input line "#card_number" when the page is loaded, the conditional alternative ( else branch) is executed silently. This is what JS looks like:

 $('#new_purchase').submit(function() { $('input[type=submit]').attr('disabled', true); if ($('#card_number').length) { purchase.processCard(); return false; } else { return true; } }); 

The behavior that you see when navigating "back" to a new page is the result of loading the page with the input in the "#card_number" field (executing the processCard function), which you need, just not when you want it.

If my assumptions are correct, correcting the indentation in your CoffeeScript is the solution.

+5
source

Is something submitting a page loading form? (Perhaps a jQuery erroneous query from another part of the application?) I found that this page helped me a lot when setting up / testing Stripe: https://stripe.com/docs/testing

UPDATE

Try first

 def new @book = Book.find(params[:book_id]) @purchase = @book.purchases.new end 

and if that doesn't work, change the form to

 <%= form_for [@book, Purchase.new] do |f| %> 
+1
source

All Articles