Ask A Question

Notifications

You’re not receiving notifications from this thread.

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 ?

Reply

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().```

Reply
funnelvisionaus funnelvisionaus

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.

Reply

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.

Reply

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.

Reply
Two errors are happening with Turbolinks and Stripe Elements v3 as this tutorial stands. One was mentioned above. I'll post the 2nd one at some point. I'd look at your example application and navigate around a little - you'll see them.
Reply

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
Reply

Great upgrade to Stripe episodes. Thank You Chris.

Reply

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

Reply

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

Reply

Thanks René, I should of figured that out.

Reply

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?

Reply

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.

Reply

Just to be clear, is this video not using the Payment Intents API?

Reply

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

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 86,796+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.