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:

  1. Add the Stripe gem
    • gem 'stripe'
    • $ bundle install
  2. 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")
                
    


  3. 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();
       }
     };
    


  4. Load the payment.js file

     # config/initializers/assets.rb
     Rails.application.config.assets.precompile += ['payments.js']
    


  5. 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