The Issue
I've tested the CoffeeScript and the form makes the call to Stripe, sets the hidden field with the proper response token and submits the form. My issue is that once its submitted the controller doesn't seem to grab the token properly and throws this error: Stripe::InvalidRequestError - You must supply either a card or a customer id.
Next I tired taking the token that was generated and hard coded it into the controller to see if that would work. I submitted the form, that worked and payment was received on Stripes end. I'm pretty much out of ideas on what to try next. I'm wondering if I am forgetting something or missing something since payments is nested under assignments.
Gem Versions
- Ruby: 2.1.0
- Rails: 4.0.1
- Stripe: 1.9.9
Files
/payment/new.html.erb
<%= form_for([@assignment, @payment]) do |f| %>
<% if @payment.errors.any? %>
<div class="error_messages">
<h2><%= pluralize(@payment.errors.count, "error") %> prohibited this subscription from being saved:</h2>
<ul>
<% @payment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :stripe_customer_token %>
<% if @payment.stripe_customer_token.present? %>
<p>This assignment has already been paid for.</p>
<% else %>
<div class="field">
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil, placeholder: "00000000000000" %>
</div>
<div class="row">
<div class="field card__dates">
<%= 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"} %>
</div>
<div class="field card__cvv">
<%= label_tag :card_code, "CVV" %>
<%= text_field_tag :card_code, nil, name: nil, placeholder: "003", required: true, maxlength: 4, minlength: 3 %>
</div>
</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 class="actions">
<%= f.submit "Pay " + number_to_currency(@assignment.price.to_s), class: 'btn btn__primary btn__large btn--fill' %>
</div>
payment_controller.rb
class PaymentsController < ApplicationController
def new
set_assignment
@payment = @assignment.build_payment
@price = @assignment.price
end
def create
set_assignment
@payment = @assignment.build_payment(payment_params)
if save_with_payment
redirect_to assignments_path, :notice => "Payment received, Thank you!"
# since payment was successful, set assignment paid to true
Assignment.update(@assignment, assignment_paid: true, project_status: "In Progress")
else
render :new
end
end
private
def save_with_payment
# Set your secret key: remember to change this to your live secret key in production
# See your keys here https://manage.stripe.com/account
Stripe.api_key = Rails.configuration.stripe[:secret_key]
# Get the credit card details submitted by the form
token = params[:stripe_customer_token]
# How much the assignment costs, which must be converted to cents
@amount = (@price * 100)
# Create the charge on Stripe's servers - this will charge the user's card
begin
charge = Stripe::Charge.create(
:amount => @amount,
:currency => "cad",
:card => token,
:description => "some description of the product"
)
rescue Stripe::CardError => e
redirect_to @assignment, :notice => "The card has been declined"
end
end
def set_assignment
@assignment = Assignment.friendly.find(params[:assignment_id])
end
def payment_params
params.require(:payment).permit(
:stripe_customer_token
)
end
end
payment.js.coffee
$ ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
payment.setupForm()
payment =
setupForm: ->
$('#new_payment').submit ->
$('input[type=submit]').attr('disabled', true)
if $('#card_number').length
payment.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, payment.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
console.log response
$('#payment_stripe_customer_token').val(response.id)
$('#new_payment')[0].submit()
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)
payment.rb
class Payment < ActiveRecord::Base
belongs_to :assignment
end