Peege151
Peege151

Reputation: 1560

Donations on Stripe with Rails

I have a form with radio buttons to select an option for the amount to donate.

That looks like this:

<tr>
  <td><input type="radio" name="amount" value="10"><span>$10</span></td>
  <td><input class="awk" type="radio" name="amount" value="25"><span>$25</span></td>
</tr>
<tr>
  <td><input type="radio" name="amount" value="50"><span>$50</span></td>
  <td><input type="radio" name="amount" value="100"><span>$100</span></td>
</tr>

There's a pay button, which opens stripes payment gateway.

for the form I have is this:

<%= form_tag charges_path, id: 'chargeForm' do %>
  <script src="https://checkout.stripe.com/checkout.js"></script>
  <%= hidden_field_tag 'stripeToken' %>
  <%= hidden_field_tag 'stripeEmail' %>
  <button id="customButton" class="btn btn-large btn-primary">Buy Now</button>

   <script>
      var handler = StripeCheckout.configure({
      key: 'foo',
      image: '/assets/my_logo.png',
      token: function(token, args) {
            document.getElementById("stripeToken").value = token.id;                              
            document.getElementById("stripeEmail").value = token.email;
            document.getElementById("chargeForm").submit();
          }
        });

      document.getElementById('customButton').addEventListener('click', function(e) {
        // Open Checkout with further options
        handler.open({
          name: 'My Company',
          description: 'Product ($60.00)',
          amount: (100 * $('input[name=amount]:checked', '#stripe_donate').val()),
          shippingAddress: false
        });
        e.preventDefault();
      });
    </script>
<% end %>

This loads the stripe modal correctly displaying the correct amount on the pay button, but how do I tell RAILS how much to charge the customer? Stripe is charging $5.00 no matter what because of the rails controller code:

class ChargesController < ApplicationController
  def new
  end

  def create
    # Amount in cents
    @amount = 500

    customer = Stripe::Customer.create(
      :email => '[email protected]',
      :card  => params[:stripeToken]
    )

    charge = Stripe::Charge.create(
      :customer    => customer.id,
      :amount      => @amount,
      :description => 'Rails Stripe customer',
      :currency    => 'usd'
    )

  rescue Stripe::CardError => e
    flash[:error] = e.message
    redirect_to charges_path
    end 
end

So How do I tell rails in the controller that the @amount needs to be set to a value received from the page? Do I just skip the rails route altogether and do this using pure JS?

Upvotes: 0

Views: 776

Answers (3)

Substantial
Substantial

Reputation: 6682

First, I moved the donation amounts into a constant and added support for an :amount attribute (assuming Rails 3.x and a model named Charge). This allows you to add or remove dollar amounts with ease, and submit the selected dollar amount with the form:

# /app/models/charge.rb
DONATION_DOLLAR_AMOUNTS = [10, 25, 50, 100]
attr_accessor :amount

In the view, move radio buttons inside the form and use proper labels. We use the constant to generate a button for each dollar amount. (I removed the table structure because a form cannot cross table rows).

<%= form_tag charges_path, id: 'chargeForm' do %>

  <!-- generate four radio buttons with labels (TODO: move this into a helper) -->
  <% Charge::DONATION_DOLLAR_AMOUNTS.each do |amt| %>       
    <%= radio_button_tag "amount", amt %>
    <%= label_tag "amount_#{amt}", number_to_currency(amt, precision: 0) %>

  <script src="https://checkout.stripe.com/checkout.js"></script>
  <%= hidden_field_tag 'stripeToken' %>
  <%= hidden_field_tag 'stripeEmail' %>
  <button id="customButton" class="btn btn-large btn-primary">Buy Now</button>
  <!-- ... -->

Pick up the value in the controller:

def create
  # Use dollar amount in param or 5 if none, then convert to cents
  @amount = (params[:amount] || 5) * 100
  # ...

Upvotes: 1

apeniche
apeniche

Reputation: 669

You should put the radio buttons inside of the form (there should only be one form) and then get that value on the controller (you might want to set the values to cents, or otherwise convert it to cents in the controller).

Upvotes: 0

Calvin Froedge
Calvin Froedge

Reputation: 16373

Do an ajax submission to the rails controller with the amount as a parameter, along with the stripe token:

(jquery)

var data = {
  'amount': $('input[name="amount"]').val(),
  'stripeToken': stripeToken //what you got from checkout.js
}
$.post( "/charges", function( data ) {
  console.log('Sent charge to controller!')
});

(rails)

  def create
    # Amount in cents
    @amount = params[:amount]

Alternatively, put everything in a form and POST to the /charges url, like you're presumably already doing to send the stripeToken.

Upvotes: 0

Related Questions