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