dmt2989 dmt2989 - 2 months ago 9
Javascript Question

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!

Answer

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 %>