Stripe Elements Javascript Discussion
Great tutorial! Seems that the new elements library is easy to use. I was wondering how would I go about implementing Stripe Elements in a e-commerce site with a React Front-End and a Rails API backend. Any ideas / suggestions ?
The below error is thrown in the console from the code in your repo. It looks like its being called on other pages as well.
```Uncaught Error: The selector you specified (#card-element) applies to no DOM elements that are currently on the page.
Make sure the element exists on the page before calling mount().```
Hi Andrew, your JS is running before the page has finished rendering. You need to move the <script> to below the HTML on the page, or put it in jQuery and wait for the DOM to stop loading.
I have an error where the iframe is not being displayed. Clicking the Submit Payment button shows the Your card number is incomplete error message. I also see the error reported by Andrew. Looking at Stackoverflow there seem to be a number of current issues with Stripe and Turbolinks.
Hi, I'm watching this as part of the Stripe MasterClass.
In subscriptions.js, my 'public_key' variable works. But when I then declare the 'stripe' variable, it doesn't seem to know what 'Stripe' is, because 'Stripe(public_key)' returns undefined. Any hints? Thanks.
Hey Chris,
Running into a small issue with Rails 5.2 and Content-Security-Policy issues with the stripe elements.
Any suggestions?
I tried poking around config > initializers > content_security_policy.rb but changes such as the following didn't do much.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
Rails.application.config.content_security_policy do |policy|
policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035' if Rails.env.development?
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
# policy.object_src :none
policy.script_src :self, :https, 'stripe.com'
# policy.style_src :self, :https
# # Specify URI for violation reports
# policy.report_uri '/csp-violation-report-endpoint'
end
Hi Chris - The Bootstrap 4 Gem, specifically @import "bootstrap/forms"; blocks the Stripe card element from dispalying.
Do you know of a work around?
Thanks,
Brian
Simply change
<div id="card-element">
<!-- a Stripe Element will be inserted here. -->
</div>
to
<div id="card-element" class="form-control">
<!-- a Stripe Element will be inserted here. -->
</div>
Afterwards the card element is shown
Hi Chris,
I'm following your Stripe Elements and Stripe Subscriptions tutorials. Currently Stripe Elements is working perfectly, but while following the subscriptions tutorial after I create the customer in the controller. Stripe is receiving 2 requests for my customer creation (3 requests total for getting the source token) and is creating one customer with the card information and one without the card information. Oddly enough both are receiving the email associated with that customer from Devise and I receive the correct one (with card details) in the customer variable. The only major differences I made from the tutorials is I converted the Stripe Elements js to coffee. I tried removing the submit action on the stripeTokenHandler function so it doesn't submit the token to the server. But it still creates one customer without card details.
Here's my code. Any help would be appreciated.
Coffee File
stripeTokenHandler = (token) ->
# Insert the token ID into the form so it gets submitted to the server
form = document.getElementById('payment-form')
hiddenInput = document.createElement('input')
hiddenInput.setAttribute 'type', 'hidden'
hiddenInput.setAttribute 'name', 'stripeToken'
hiddenInput.setAttribute 'value', token.id
form.appendChild hiddenInput
[
'brand'
'exp_month'
'exp_year'
'last4'
].forEach (field) ->
addFieldToForm form, token, field
return
console.log token
# Submit the form
form.submit()
return
addFieldToForm = (form, token, field) ->
hiddenInput = document.createElement('input')
hiddenInput.setAttribute 'type', 'hidden'
hiddenInput.setAttribute 'name', 'card_' + field
hiddenInput.setAttribute 'value', token.card[field]
form.appendChild hiddenInput
return
document.addEventListener 'turbolinks:load', ->
public_key = document.querySelector('meta[name=\'stripe-public-key\']').content
stripe = Stripe(public_key)
elements = stripe.elements()
# Custom styling can be passed to options when creating an Element.
style = base:
fontSize: '16px'
color: '#32325d'
# Create an instance of the card Element.
card = elements.create('card', style: style)
# Add an instance of the card Element into the `card-element` <div>.
card.mount '#card-element'
card.addEventListener 'change', (event) ->
displayError = document.getElementById('card-errors')
if event.error
displayError.textContent = event.error.message
else
displayError.textContent = ''
return
# Create a token or display an error when the form is submitted.
form = document.getElementById('payment-form')
form.addEventListener 'submit', (event) ->
event.preventDefault()
stripe.createToken(card).then (result) ->
if result.error
# Inform the customer that there was an error.
errorElement = document.getElementById('card-errors')
errorElement.textContent = result.error.message
else
# Send the token to your server.
stripeTokenHandler result.token
return
return
return
Controller
class ChargesController < ApplicationController
before_action :authenticate_user!, only: [:show, :new, :create]
before_action :set_user, only: [:create]
def show
end
def new
end
def create
customer = Stripe::Customer.create({
source: params[:stripeToken],
email: @user.email
})
raise customer
end
private
def set_user
@user = current_user
end
end
View:
<%= form_with url: charges_path, id: 'payment-form' do |form| %>
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element">
<!-- A Stripe Element will be inserted here. -->
</div>
<!-- Used to display Element errors. -->
<div id="card-errors" role="alert"></div>
</div>
<button>Submit Payment</button>
<% end %>
Any thoughts?
To anyone having this same problem, and since Chris doesn't seem to respond to this video's comments. If you are using form_with
to render the form, you must add local: true
to it. As form_with automatically uses remote: true
to submit via XMLHttpRequest. This should stop your server from double submitting.
Same question as @jose, does anyone know if this [1] covers two factor / 3D Secure payments using the payment intents API from Stripe? Thanks!
[1] https://courses.gorails.com/payments-with-rails-master-class