Dealing with payments in your app via Stripe
Charging credit cards in your Ruby on Rails app with Stripe is not only simple, but also secure. Sensible credit card information doesn’t flow through the servers of your app, which frees you from complying with regulatory obligations.
Stripe has extensive documentation and I especially recommend these resources:
- https://stripe.com/docs/tutorials/forms
- https://gist.github.com/briancollins/6365455
- https://stripe.com/docs/api/ruby#charges
- Add the Stripe gem
gem 'stripe'
$ bundle install
- Create your html form
- Reference the Stripe javascript file (not in the general form header, but just on this page).
- Set your publishable Stripe key in the header.
- Include the payments.js file (We’ll create it later).
- Give your form an id that your payments.js file can refer to (
id: "payment-form"
in this case). - Make sure your credit card form fields don’t have name attributes, so the data won’t be submitted to your app’s server.
- Add the
data-stripe
tag to your credit card form fields (data-stripe="number"
). - Add a span tag with id “payment-errors”, which payments.js will use to include errors in case the credit card charge doesn’t go through.
<!-- app/views/users/new.html.haml --> = content_for :head do %script(type="text/javascript" src="https://js.stripe.com/v2/") :javascript Stripe.setPublishableKey('#{ENV['STRIPE_PUBLISHABLE_KEY']}'); = javascript_include_tag 'payments' %section.register.container .row .col-sm-10.col-sm-offset-1 = bootstrap_form_for @user, layout: :horizontal, label_col: "col-sm-2", control_col: "col-sm-6", html: {id: "payment-form"} do |f| %header %h1 Register %fieldset = f.email_field :email, label: "Email Address" = f.password_field :password = f.text_field :full_name, label: "Full Name" %fieldset.credit_card %span.payment-errors .form-group %label.control-label.col-sm-2 Credit Card Number .col-sm-6 %input.form-control(type="text" data-stripe="number") .form-group %label.control-label.col-sm-2 Security Code .col-sm-6 %input.form-control(type="text" data-stripe="cvc") .form-group %label.control-label.col-sm-2 Expiration .col-sm-3 = select_month(Date.today, {add_month_numbers: true}, class: 'form-control', data: {stripe: "exp-month"}) .col-sm-2 = select_year(Date.today.year, {start_year: Date.today.year, end_year: Date.today.year + 4}, class: 'form-control', data: {stripe: "exp-year"}) %fieldset.actions.control-group.col-sm-offset-2 .controls %input(type="submit" value="Sign Up" class="btn btn-default")
- Create the
payments.js
file- The javascript code is provided by Stripe and can be found here.
// app/assets/javascripts/payments.js jQuery(function($) { $('#payment-form').submit(function(event) { var $form = $(this); // Disable the submit button to prevent repeated clicks $form.find('button').prop('disabled', true); Stripe.card.createToken($form, stripeResponseHandler); // Prevent the form from submitting with the default action return false; }); }); function stripeResponseHandler(status, response) { var $form = $('#payment-form'); if (response.error) { // Show the errors on the form $form.find('.payment-errors').text(response.error.message); $form.find('button').prop('disabled', false); } else { // response contains id and card, which contains additional card details var token = response.id; // Insert the token into the form so it gets submitted to the server $form.append($('<input type="hidden" name="stripeToken" />').val(token)); // and submit $form.get(0).submit(); } };
- The javascript code is provided by Stripe and can be found here.
-
Load the payment.js file
# config/initializers/assets.rb Rails.application.config.assets.precompile += ['payments.js']
- Handle the Stripe charge in the controller action
- The Ruby code for charging the credit card is also provided by Stripe here.
# app/controllers/users_controller.rb # code omitted for brevity def create @user = User.new(user_params) if @user.save handle_invitation handle_payment_with_stripe AppMailer.delay.send_welcome_email(@user) redirect_to login_path else render :new end end def handle_payment_with_stripe Stripe.api_key = ENV["STRIPE_SECRET_KEY"] Stripe::Charge.create( :amount => 999, :currency => "gbp", :source => params[:stripeToken], # obtained with Stripe.js :description => "Sign up charge for #{@user.email}" ) end