Reputation: 10241
Stripe will not accept payments, the charge keeps failing. I am getting this error:
Started POST "/charges" for 127.0.0.1 at 2014-06-09 06:30:58 -0700
Processing by ChargesController#create as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"9bqk2Q6NEM1ehHDJPgncNQ3gnP0X1hQK6y6ENm3Yb1g=", "c
harge"=>{"contest_id"=>"36", "user_id"=>"", "amount"=>"12", "stripe_card_token"=>""}, "card_number"=
>"4242 4242 4242 4242", "card_code"=>"478", "button"=>""}
Stripe error while creating customer: You passed an empty string for 'card'. We assume empty values
are an attempt to unset a parameter; however 'card' cannot be unset. You should remove 'card' from y
our request or supply a non-empty value
Redirected to http://localhost:3000/
Completed 302 Found in 477ms (ActiveRecord: 0.0ms)
It seems as if it might not be creating the stripe token? What is going on here?
This is my form:
<% content_for :head do %>
<%= tag :meta, :name => "stripe-key", :content => STRIPE_PUBLIC_KEY %>
<% end %>
<%= form_for @charge, :html => { :class => 'form' } do |f| %>
<div class="form-inputs">
<div class="row">
<%= f.hidden_field :contest_id, value: @contest.id %>
<%= f.hidden_field :user_id %>
<%= f.hidden_field :amount %>
<!-- TODO CHANGE THIS ACCORDINGLY -->
<%= f.hidden_field :stripe_card_token %>
<div class="small-12 medium-6 large-2 columns">
<%= f.label "Amount:", class: "text-right" %>
</div>
<div class="small-12 medium-6 large-10 columns" style="margin-bottom: 0.5rem; margin-top: 0.5rem;">
<%= number_to_currency(@charge.amount, :unit => "$") %>
</div>
<% if @charge.stripe_card_token.present? %>
Credit card has been provided.
<% else %>
<div class="small-12 medium-6 large-2 columns">
<%= label_tag :card_number, "Credit Card Number:", class: "text-right" %>
</div>
<div class="small-12 medium-6 large-10 columns">
<%= text_field_tag :card_number %>
</div>
<div class="small-12 medium-6 large-2 columns">
<%= label_tag :card_code, "Security Code on Card (CVV):", class: "text-right" %>
</div>
<div class="small-12 medium-6 large-10 columns end">
<%= text_field_tag :card_code %>
</div>
<div class="small-12 medium-6 large-2 columns">
<%= label_tag :card_month, "Card Expiration:", class: "text-right" %>
</div>
<div class="small-6 medium-3 columns">
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
</div>
<div class="small-6 medium-3 columns">
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
</div>
<% 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>
</div>
<div class="row">
<div class="form-actions small-9 small-offset-2 columns">
<%= button_tag :type => "button", :class => "radius" do %>
<%= link_to "Back", @contest, :style => "color: white" %>
<% end %>
<%= f.button :Donate, :class => "radius" %>
</div>
</div>
</div>
<% end %>
<% content_for :js do %>
<%= javascript_include_tag "https://js.stripe.com/v1", "application" %>
<%= javascript_include_tag asset_path("stripe/stripe.js"), "application" %>
<% end %>
This is my charges controller:
class ChargesController < ApplicationController
def new
@contest = Contest.find(params[:id])
@charge = Charge.new(amount: params[:amount])
end
def create
@charge = Charge.new(charges_params)
if @charge.save_with_payment(@charge)
redirect_to root_path, :notice => "Contribution was recorded succesfully!"
else
redirect_to root_path, :notice => "Transaction was not able to be recorded"
end
end
def charges_params
params.require(:charge).permit(:stripe_card_token, :contest_id, :user_id, :amount)
end
end
My Charge Model:
class Charge < ActiveRecord::Base
attr_accessor :stripe_card_token
belongs_to :contest
belongs_to :user
def save_with_payment(charge)
if valid?
Stripe::Charge.create(
:amount => (charge.amount.to_i)*100,
:currency => "usd",
:card => stripe_card_token);
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
Upvotes: 3
Views: 9144
Reputation: 3333
I encountered the same problem.
my subscription.js.coffee:
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
subscription.setupForm()
subscription =
setupForm: ->
$('#new_subscription').submit (e) ->
$('input[type=submit]').attr('disabled', true)
subscription.processCard()
return false
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
expMonth: $('#card_month').val()
expYear: $('#card_year').val()
Stripe.createToken(card, subscription.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
$('#subscription_stripe_card_token').val(response.id)
$('#new_subscription')[0].submit()
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)
false
As you can see when user pushes submit
button the function $('#new_subscription').submit (e)
is raised. There is almost all of the stripe magic in the submit function.
In my case sometimes the submit function is not raised therefore empty stripe_card_toke
parameter is sent to your server.
The strange behavior is caused by Rails turbolinks facilities.
I solved it in such way:
gem 'jquery-turbolinks'
//= require jquery.turbolinks
//= require jquery //= require jquery.turbolinks //= require jquery_ujs //= require turbolinks //= require bootstrap //= require jquery_nested_form //= require_tree .
Upvotes: -1
Reputation: 4288
Unrelated to stripe_card_token
being blank, your server is currently in PCI scope because it's receiving the card number and CVV code. This is probably not what you're intending if you're using Stripe.
From the Stripe Getting Started docs:
Note how input fields representing sensitive card data (number, CVC, expiration month and year) do not have a "name" attribute. This prevents them from hitting your server when the form is submitted.
Rails tag helpers generate a name attribute by default. That's not desirable in this case.
You can override this behavior by passing nil for both name
and value
, and defining an identifier of some kind:
<%= text_field_tag nil, nil, 'data-stripe' => 'card_number' %>
Here I've used Stripe's currently-recommended data-stripe
, but you can just as well use the id
attribute (as their older tutorials recommended).
Getting back to your original question, the problem is in your Charge model, where you're overriding Active Record and masking the data in the database:
class Charge < ActiveRecord::Base
attr_accessor :stripe_card_token # Don't do this!
attr_accessor
should never be used on database columns. Active Record provides its own accessors in order to pull that data from the database; by declaring an accessor here, you're replacing Active Record's functionality with Ruby's base functionality:
irb(main):001:0> Charge.first
Charge Load (0.3ms) SELECT "charges".* FROM "charges" ORDER BY "charges"."id" ASC LIMIT 1
=> #<Charge id: 1, stripe_card_token: "0xdeadbeef", created_at: "2014-06-11 14:27:40", updated_at: "2014-06-11 14:27:40">
irb(main):002:0> c.stripe_card_token
=> nil
That being said, the Railscast you started from is nearly three years old, violates best practices all over the place, and uses a long-outdated API endpoint. Once you correct your model, you're still better off starting your form and JavaScript over using Stripe's current tutorial and documentation.
Upvotes: 0
Reputation: 1398
Most likely it looks like stripe_card_token is blank as its
:card => stripe_card_token
try and change that to
:card => charge.stripe_card_token
Upvotes: 0