How to ask for custom amount with Stripe in Rails? - ruby-on-rails

I am attempting to follow the Stripe/Rails tutorial to enable customers to choose how much they want to pay: https://stripe.com/docs/recipes/variable-amount-checkout.
When I try to do this, I keep getting an error saying:
You have passed a blank string for 'source'. You should remove the 'source' parameter from your request or supply a non-blank value.
Stripe::Charge.create(
:amount => #amount,
:currency => 'usd',
:source => params[:stripeToken],
I believe this is because the params[:stripeToken] isn't being set. Any advice on how to fix this?
Current new.html.erb
<script src="https://checkout.stripe.com/checkout.js"></script>
<script>
var handler = StripeCheckout.configure({
key: '<%= Rails.configuration.stripe[:publishable_key] %>',
locale: 'auto',
name: 'Sand Castles United',
description: 'One-time donation',
token: function(token) {
$('input#stripeToken').val(token.id);
$('form').submit();
}
});
$('#donateButton').on('click', function(e) {
e.preventDefault();
$('#error_explanation').html('');
var amount = $('input#amount').val();
amount = amount.replace(/\$/g, '').replace(/\,/g, '')
amount = parseFloat(amount);
if (isNaN(amount)) {
$('#error_explanation').html('<p>Please enter a valid amount in USD ($).</p>');
}
else if (amount < 5.00) {
$('#error_explanation').html('<p>Donation amount must be at least $5.</p>');
}
else {
amount = amount * 100; // Needs to be an integer!
handler.open({
amount: Math.round(amount)
})
}
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
</script>
<%= form_tag charges_path do %>
<div id="error_explanation">
<% if flash[:error].present? %>
<p><%= flash[:error] %></p>
<% end %>
</div>
<article>
<%= label_tag(:amount, 'Donation Amount:') %>
<%= text_field_tag(:amount) %>
</article>
<article>
<%= hidden_field_tag(:stripeToken) %>
</article>
<button id='donateButton'>Donate</button>
<% end %>

Related

Using multiple Stripe checkout buttons, all items use last items price and name on rails

I'm working on a simple store front, and wanted to use stripe checkout buttons for the items. I have a DB of items that I'm iterating through, and generating payment buttons for with JS, here's that code:
<%= form_tag charges_path, id: 'stripeForm' do -%>
<script src="https://checkout.stripe.com/checkout.js"></script>
<%= hidden_field_tag 'stripeToken' %>
<%= hidden_field_tag 'stripeEmail' %>
<%= hidden_field_tag 'stripeAmount' %>
<p>
<% puts p.name %>
<% #price= p.price %>
Buy <% p.name %> for <% number_to_currency(#price, :unit=> '$') %>
<button id="<%=p.id %>">Purchase: <%=p.name%></button>
</p>
<script>
var handler = StripeCheckout.configure({
key: '<%= Rails.configuration.stripe[:publishable_key] %>',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: function(token, args) {
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#stripeAmount").val('<%= #price %>');
$("#stripeForm").submit();
}
});
document.getElementById('<%= p.id %>').addEventListener('click', function(e) {
handler.open({
name: 'Malus Cider',
description: '<%=p.name%>',
shippingAddress:true,
billingAddress:true,
amount: <%= #price %>
});
e.preventDefault();
});
window.addEventListener('popstate', function() {
handler.close();
});
</script>
<% end %>
<% end %>
my controller:
def create
# Amount in cents
amount = params[:stripeAmount].to_i * 100
puts amount
# Create the customer in Stripe
customer = Stripe::Customer.create(
email: params[:stripeEmail],
source: params[:stripeToken]
)
# Create the charge using the customer data returned by Stripe API
charge = Stripe::Charge.create(
customer: customer.id,
amount: amount,
description: 'Rails Stripe customer',
currency: 'usd'
)
end
private
def product_params
params.require(:product).permit(:id, :name, :price)
end
this works! Except that at the last second the hidden field values change to the last item in the DB. So it almost works. Any ideas?

How to display a selection based on user input using ajax and jquery

Think of the below as a bike rental. Someone fills out a form and gets a bike assigned to them which they can rent and borrow for a certain amount of time.
The problem I am having is I am trying to show the person who wants to rent the bikes what bikes are available before they submit the form. Below is my attempt using ajax. I have no errors but also my select is not updating.
request controller methods below
def new
#bikes = Bike.available_based_on_request_date(params[:Borrow_date], params[:Return_date])
#new_request = Request.new
end
create method below (with a temporary workaround, that reloads the form with a warning about availability.)
def create
#request = Request.new(request_params)
available_bikes = #request.new_request(current_user.id)
if (available_bikes >= #request.number_of_bikes_wanted) && #request.save
redirect_to root_path
else
flash[:warning] = "You have requested more bikes than available. There are only #{available_bikes} bikes available"
redirect_to new_request_url
end
end
params in request controller
def request_params
params.require(:request).permit(:Borrow_time, :Borrow_date,
:Return_date, :Return_time,
:number_of_bikes_wanted, bike_ids: [])
end
new.html.erb view
<div class="form" align = "center">
<%= render 'form.js.erb' %>
</div>
_form.js.erb below
<script type="text/javascript">
$(document).ready(function() {
$('.my-date').on('change', function() {
var data = {}
$('.my-date').each(function() {
if($(this).val()) {
data[$(this).attr("id")] = $(this).val();
}
});
if(Object.keys(data).length > 1) {
$.ajax({
type: "POST",
url: <%= new_request_path %>,
data: data
});
}
});
});
var options = "";
<% #bikes.each do |bike| %>
options += "<option value='<%= bike.id %>'><%= bike.name %></option>"
<% end %>
$('#request_number_of_bikes_wanted').html(options);
</script>
<div class="block-it" align=center>
<br>
<%= form_for #new_request do |request| %>
<%= request.label :Borrow_date, 'Borrow on' %>
<%= request.date_field :Borrow_date, id: 'Borrow_date', class: 'my-date', min: Date.today, :required => true %>
<%= request.label :Borrow_time, 'Borrow at' %>
<%= request.time_field :Borrow_time, value: '10:00', min: '9:00 AM', max: '4:30 PM', default: '10:00 AM', :ignore_date => true, :required => true %>
<br><br>
<%= request.label :Return_date, 'Return On' %>
<%= request.date_field :Return_date, id: 'Return_date', class: 'my-date', min: Date.today, :required => true %>
<%= request.label :Return_time, 'Return at' %>
<%= request.time_field :Return_time, value: '10:00', min: '9:00 AM', max: '4:30 PM', default: '10:00 AM', :ignore_date => true, :required => true %>
<br><br>
<br><br>
<%= request.label :NumberOfBikesWanted, 'Number of bikes' %>
<%= request.select :number_of_bikes_wanted, %w(select_bike), :required => true %>
<br>
<%= request.submit 'Submit' %>
<%= request.submit 'Reset', :type => 'reset' %>
<% end %>
<br>
</div>
There are a two main problems with your code:
Controller
Use a different action to set the endpoint that you will call with ajax, so instead of this:
def new
#bikes = Bike.available_based_on_request_date(params[:Borrow_date], params[:Return_date])
#new_request = Request.new
end
Try this:
def bikes
#bikes = Bike.available_based_on_request_date(params[:Borrow_date], params[:Return_date])
def new
#new_request = Request.new
end
If you want to keep REST routes, then create a new controller and use the index action within that controller.
Form
This code:
var options = "";
<% #bikes.each do |bike| %>
options += "<option value='<%= bike.id %>'><%= bike.name %></option>"
<% end %>
$('#request_number_of_bikes_wanted').html(options);
doesn't belong here, it must be deleted from your file and instead put it on a new file called bikes.js.erb; also rename your form to _form.html.erb.
And update your ajax call to use your new route:
$.ajax({
type: "POST",
url: <%= bikes_path %>,
data: data
});
What you want to setup is a new endpoint but instead of returning html, it will return a js. But you must treat it as an independent action, just as any other action in rails. The only difference is how you call that action (ajax) and how you respond to it (js).

Stripe payments routes charging the same for different charge buttons

I am trying to add two buttons to my payment platform. But stripe is charging me the same amount even when the other button is pressed. This is my attempt but it isn't working. I am not sure what is going wrong.
charges_controller.rb
def create
# Amount in cents - €1000.00
#amount = 100000
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:description => 'Thanks, on behalf of CMRF',
:currency => 'eur'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
View
<%= 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">Sponsor a Hole</button>
<script>
var handler = StripeCheckout.configure({
key: '<%= ENV["PUBLISHABLE_KEY"] %>',
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: 'Entry (€1000.00)',
currency: 'eur',
amount: 100000,
billingAddress: true,
});
e.preventDefault();
});
</script>
<% end %>
<%= form_tag charges_path, id: 'chargeForm1' do %>
<script src="https://checkout.stripe.com/checkout.js"></script>
<%= hidden_field_tag 'stripeToken' %>
<%= hidden_field_tag 'stripeEmail' %>
<button id="customButton1" class="btn btn-large btn-success">Enter A Team</button>
<script>
var handler = StripeCheckout.configure({
key: '<%= ENV["PUBLISHABLE_KEY"] %>',
// 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('customButton1').addEventListener('click', function(e) {
// Open Checkout with further options
handler.open({
name: 'My Company',
description: 'Sponsor (€200.00)',
currency: 'eur',
amount: 20000,
billingAddress: true,
// shippingAddress: true
});
e.preventDefault();
});
</script>
<% end %>
Routes.rb
Rails.application.routes.draw do
resources :charges
root 'pages#index'
get 'pages/about'
get 'pages/contact'
get 'pages/pay'
The amount and currency parameters that you pass to Checkout (in the call to handler.open(...)) are used for display purposes only.
The actual amount and currency that are used for the charge are the ones you provide in the amount and currency parameters of the charge creation request that is sent by your backend code.
In this case, the charge is created in your charges_controller.rb file, and the amount is fixed. If you want to charge different amounts, you'd need to send some other field along with the token so that your backend code can know which amount to charge.
Unless the amount is explicitly set by the customer (e.g. if you're accepting donations), you should not rely on an amount that is provided by the customer's browser as it would be very easy to change it. Instead, you likely want to use some identifier that you can use in your backend code to retrieve the correct amount.

Stripe standalone :source => params[:stripeToken] error

I'm new to Stripe connect, building a marketplace app using stripe connect standalone, and require the user to enter a custom amount to pay the other user. The old form I was using worked fine, but once I changed to the new form, my :source => params[:stripeToken] no longer generates, as well as :stripeEmail. What is causing this?
Invalid source object: must be a dictionary or a non-empty string
my original charges_controller.rb
class ChargesController < ApplicationController
def new
end
def create
# Amount in cents
#amount = 500
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:description => 'Wage Payment',
:currency => 'cad'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
then I added the methods from the stripe recipe for custom amounts:
def create
#amount = params[:amount]
#amount = #amount.gsub('$', '').gsub(',', '')
begin
#amount = Float(#amount).round(2)
rescue
flash[:error] = 'Charge not completed. Please enter a valid amount in CAD ($).'
redirect_to new_charge_path
return
end
#amount = (#amount * 100).to_i # Must be an integer!
if #amount < 500
flash[:error] = 'Charge not completed. Payment amount must be at least $5.'
redirect_to new_charge_path
return
end
charge = Stripe::Charge.create(
:amount => #amount,
:customer => customer.id,
:currency => 'cad',
:source => params[:stripeToken],
:description => ‘Payment'
)
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
I also modified the form, and added the javascript in charges/new.html.erb:
old form:
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
Stripe.setPublishableKey('pk_test_my_key');
</script>
<%= form_tag charges_path do %>
<article>
<% if flash[:error].present? %>
<div id="error_explanation">
<p><%= flash[:error] %></p>
</div>
<% end %>
<label class="amount">
<span>Amount: $5.00</span>
</label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500"
data-locale="auto"></script>
<% end %>
new form:
<%= form_tag charges_path, id: 'form' do %>
<div id="error_explanation">
<% if flash[:error].present? %>
<p><%= flash[:error] %></p>
<% end %>
</div>
<article>
<%= label_tag(:amount, 'Payment Amount:') %>
<%= text_field_tag(:amount) %>
</article>
<article>
<%= hidden_field_tag(:stripeToken) %>
<%= hidden_field_tag(:stripeEmail) %>
</article>
<button id='donateButton'>Pay Now</button>
<% end %>
<script src="https://checkout.stripe.com/checkout.js"></script>
<script type="text/javascript">
Stripe.setPublishableKey('pk_test_CcUZ1IJxEqLR5RvVE3p5tx3U');
</script>
<script>
var handler = StripeCheckout.configure({
key: '<%= Rails.configuration.stripe[:publishable_key] %>',
locale: 'auto',
name: 'Payments',
description: 'Wage',
token: function(token) {
$('input#stripeToken').val(token.id);
$('input#stripeEmail').val(token.id);
$('form').submit();
}
});
$('#donateButton').on('click', function(e) {
e.preventDefault();
$('#error_explanation').html('');
var amount = $('input#amount').val();
amount = amount.replace(/\$/g, '').replace(/\,/g, '')
amount = parseFloat(amount);
if (isNaN(amount)) {
$('#error_explanation').html('<p>Please enter a valid amount in CAD ($).</p>');
}
else if (amount < 5.00) {
$('#error_explanation').html('<p>Wage amount must be at least $5.</p>');
}
else {
amount = amount * 100; // Needs to be an integer!
handler.open({
amount: Math.round(amount)
})
}
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
</script>
Now when I submit the custom amount, I am given the following error:
You have passed a blank string for 'source'. You should remove the
'source' parameter from your request or supply a non-blank value
Extracted source (around line #27): Stripe::Charge.create(
Not sure how to proceed. This error seems to be associated to creating charges, as the error is in the charges controller. Or it is in the javascript of the new custom form.
What am I missing?
I had exactly the similar problem. But after few hours of struggle I figured it out. The reason is following. If you are using Rails 4.+ and using Turbolinks along with it, then it loads entire javascript for that page and when you are loading modal the javascript on that modal page wont work. You have to switch off the turbolink.
For me I switched off at the link level which is the link responsible for loading the charge/new page. Example:
<%= link_to "Buy", new_charge_path(product_id: #product.id),'data-no-turbolink' => true %>

Stripe / Rails Issue: "Invalid source object: must be a dictionary or a non-empty string"

I'm building a custom checkout form in my rails app and getting this error when posting to the controller:
"Invalid source object: must be a dictionary or a non-empty string"
Here's my form:
<script src="https://checkout.stripe.com/checkout.js"></script>
<%= form_tag registrations_path, :id=>"stripeForm" do |f| %>
<h2>Register for the <%= #workshop.name %> Workshop ($<%= #workshop.price %>)</h2>
<div class="row">
<div class="form-group col-sm-6">
<%= text_field_tag(:f_name, nil, :placeholder=>"First Name", :class=>"form-control") %>
</div>
<div class="form-group col-sm-6">
<%= text_field_tag(:l_name, nil, :placeholder=>"Last Name", :class=>"form-control") %>
</div>
</div>
<div class="row text-center">
<button class="buy-button" id="stripe-button">Buy Ticket</button>
<%= hidden_field_tag 'stripeToken' %>
<%= hidden_field_tag 'stripeEmail' %>
<%= hidden_field_tag 'stripeAmount' %>
</div>
<script>
var handler = StripeCheckout.configure({
key: "<%= ENV['stripe_publishable_key'] %>",
token: function (token, args) {
$("#stripeToken").value = token.id;
$("#stripeEmail").value = token.email;
$("#stripeAmount").value = <%= #workshop.price * 100 %>;
$("#stripeForm").submit();
}
});
$('#stripe-button').on('click', function (e) {
// Open Checkout with further options
$name = $('input[name=f_name]').val() + " " + $('input[name=l_name]').val();
handler.open({
name: $name,
description: "<%= #workshop.name %>" + " workshop",
amount: <%= #workshop.price * 100 %>
});
e.preventDefault();
});
$(window).on('popstate', function() {
handler.close();
});
</script>
<% end %>
Here's my controller action:
def create
# Amount in cents
amount = params[:stripeAmount].to_i * 100
# Create the customer in Stripe
customer = Stripe::Customer.create(
email: params[:stripeEmail],
card: params[:stripeToken]
)
# Create the charge using the customer data returned by Stripe API
charge = Stripe::Charge.create(
customer: customer.id,
amount: amount,
description: 'Rails Stripe customer',
currency: 'usd'
)
# place more code upon successfully creating the charge
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
flash[:notice] = "Please try again"
end
Basically the user fills out first and last name, clicks on pay button. Then they fill out stripe info and submit. I've tried using debugger right after they click submit, and all the token info etc is there as it should be.
But then I get an error as soon as it gets to the create action in the controller, and shows empty strings for all the stripe params.
Where am I going wrong?
Edit: added below strong params to the controller but had no effect:
protected
def registration_params
params.require(:registration).permit(:stripeEmail, :stripeToken, :stripeAmount)
end
Looks like a minor issue with your jQuery. The token is there, but it doesn't look like its being submitted through the form. That should be the reason Stripe is complaining about an empty string. Try this instead:
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#stripeAmount").val('<%= j #workshop.price * 100 %>');
The issue arises only when you try to update the user subscription but the payment source is not attached with the Stripe customer.
If you are trying to update subscription from Trial to Paid then please take a look at the answer which may helps you out.

Resources