dmt2989
dmt2989

Reputation: 1620

Multiple stripe payment buttons on one page of rails 4 app

I'm building a payment page that lists three different subscription options and am using Stripe's checkout to manage the payments.

The page is rendering properly, and all 3 subscription options have the "buy now" button that should be linked to Stripe.

My issue is that the first button is the only one that is properly pulling up the Stripe checkout flow. Buttons 2 and 3 throw the following error:

Unknown action The action 'index' could not be found for ChargesController

The relevant part of my payment page is:

  <% @plans.each do |plan| %>
    <li class="col-md-3 plan <%= 'plan-primary' if plan.highlight? %>">
      <div class="img-thumbnail">
        <div class="caption">
          <h3><%= plan.name %></h3>
          <h4><%= plan_price(plan) %></h4>
          <div class="call-to-action">
            <% if @subscription.nil? %>
             <% if plan.highlight? %>

              <%= form_tag main_app.charges_path do %>
                <script src="https://checkout.stripe.com/checkout.js"></script>

                  <button id="customButton" class="btn btn-success">Buy Now</button>

                  <script>
                    var handler = StripeCheckout.configure({
                      key: '<%= 'pk_test_my_pk' %>',
                      image: '/assets/my_logo.png',
                      token: function(response) {
                        var tokenInput = $("<input type=hidden name=stripeToken />").val(response.id);
                        var emailInput = $("<input type=hidden name=stripeEmail />").val(response.email);
                        $("form").append(tokenInput).append(emailInput).submit();
                      }
                    });

                    document.getElementById('customButton').addEventListener('click', function(e) {
                      handler.open({
                        name: 'My Co',
                        description: 'Listing subsctiption ($50.00)',
                        amount: 50*100,
                        shippingAddress: false
                      });
                      e.preventDefault();
                    });
                  </script>
              <% end %>

              <% else %>
               <%= form_tag main_app.charges_path do %>
                <script src="https://checkout.stripe.com/checkout.js"></script>

                  <button id="customButton" class="btn btn-large btn-primary">Buy Now</button>

                  <script>
                    var handler = StripeCheckout.configure({
                      key: '<%= 'pk_test_my_pk' %>',
                      image: '/assets/my_logo.png',
                      token: function(response) {
                        var tokenInput = $("<input type=hidden name=stripeToken />").val(response.id);
                        var emailInput = $("<input type=hidden name=stripeEmail />").val(response.email);
                        $("form").append(tokenInput).append(emailInput).submit();
                      }
                    });

                    document.getElementById('customButton').addEventListener('click', function(e) {
                      // Open Checkout with further options
                      handler.open({
                        name: 'My Co',
                        description: 'Listing subsctiption ($40.00)',
                        amount: 40*100,
                        shippingAddress: false
                      });
                      e.preventDefault();
                    });
                  </script>
              <% end %>


            <% end %>

Ideas on why only one of the 3 buttons is working properly?

Thanks!

Upvotes: 7

Views: 5135

Answers (4)

Jordan Roberts
Jordan Roberts

Reputation: 11

I know this is old, but I resolved this issue by changing the name of the handler variables (each one should have a different name) instead of changing the HTML ID's.

Upvotes: 1

JeffD23
JeffD23

Reputation: 9298

I recently encountered this problem and wanted to leave an alternative solution. In our app, we have two buttons on the page using stripe.js: "Buy Item" or "Pro Subscription". This method uses jQuery to just remove the second button from the DOM when the first one is clicked. If the user cancels the payment, the button is rendered back into the DOM. This is how the handler might look:

$('#firstButton').on('click', function() {
  $('#secondButton').html(""); // Remove the second stripe script from the dom

  handler.open({
    // handler stuff
    closed: function(){
      $('#secondButton').html('<%= j render partial: "second_button" %>'); // Renders button back to the DOM if payment is cancelled. 
      }
  });
});

Upvotes: 0

nruth
nruth

Reputation: 1068

You can get it to seem to work by having unique button ids, e.g.

<button id="<%= dom_id(pricing, 'btn') %>

but there is another problem, with the stripe js. If you execute StripeCheckout.configure multiple times it will create multiple iframes with the same name attribute. Unfortunately this means whatever your customer tries to buy, they will always be sold the last thing you inserted, even if the stripe popup said it was selling them something else.

We used this solution: one form, and dynamically inserting the price and times:

<%= form_tag charges_path, id: 'stripe-payment-form' do %>
  <%= hidden_field_tag 'amount', nil, id: 'payment_amount' %>
  <%= hidden_field_tag 'name', nil, id: 'payment_name' %>
  <%= hidden_field_tag 'days', nil, id: 'payment_days'  %>

  <% Pricing.all.each do |pricing| %>
    <p>
      <button id="<%= dom_id(pricing, 'btn') %>">
        Buy <%= pricing.name %> for <%= number_to_currency(pricing.pounds, unit: '£') %>
      </button>
    </p>
  <% end %>

  <%= javascript_tag do %>
    var handler = StripeCheckout.configure({
      key: "<%= Rails.configuration.stripe[:publishable_key] %>",
      image: "<%= image_path('/images/apple-icons/apple-touch-icon-144x144-precomposed.png') %>",
      token: function(token, args) {
        var form = $('#stripe-payment-form');
        // Use the token to create the charge with a server-side script.
        // You can access the token ID with `token.id`
        form.append($('<input type="hidden" name="stripeToken" />').val(token.id));
        form.submit();
      }
    });

    <% Pricing.all.each do |pricing| %>
      document.getElementById('<%= dom_id(pricing, 'btn') %>').addEventListener('click', function(e) {
        e.preventDefault();
        var form = $('#stripe-payment-form');
        // set the price etc for the button clicked
        $('#payment_amount').val("<%= pricing.pence %>");
        $('#payment_name').val("<%= pricing.name %>");
        $('#payment_days').val("<%= pricing.days %>");
        // Open Checkout with further options
        handler.open({
          name: 'Company name',
          currency: 'GBP',
          description: '<%= pricing.name %>',
          amount: '<%= pricing.pence %>',
          email: '<%= member.email %>',
        });
      });
    <% end %>
  <% end %>
<% end %>

Upvotes: 4

Lou Harwood
Lou Harwood

Reputation: 51

I came across the same problem in my own app recently.

All three of your buttons have the same ID.

Upvotes: 3

Related Questions