I'm using Rails, Devise and Stripe for a SaaS application and I'm having trouble saving the customers card information at the point of sign up.
The reason I want to save the information without charging is because it's a subscription plan with a free trial.
So far I can get the card token to be created and the customer to be created and they both appear in the Stripe dashboard logs (POST /v1/tokens and POST /v1/customer).
The problem is the card is not then showing as saved for the customer, i.e. they are both being submitted but they are not connected.
I think it has something to do with how I'm creating my customer in my User model:
Stripe::Customer.create(description: plan_id, email: email, plan: plan_id, card: stripeToken)
But I can't seem to find a solution.
Here is my form:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), :html => {:id => "payment-form"}) do |f| %>
<%= devise_error_messages! %>
<%= hidden_field_tag 'plan', params[:plan] %>
<div class="field form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, class: 'form-control' %>
</div>
<div class="field form-group">
<%= f.label :password %>
<% if @validatable %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off", class: 'form-control' %>
</div>
<div class="field form-group">
<%= f.label :password_confirmation, "Password Confirmation" %><br />
<%= f.password_field :password_confirmation, autocomplete: "off", class: 'form-control' %>
</div>
<!-- CC -->
<div class="form-row">
<label for="card-element">
Credit or Debit Card
</label>
<div id="card-element" class="form-control"></div>
<!-- Used to display form errors -->
<div id="card-errors" role="alert"></div>
</div>
<!-- / CC -->
<div class="actions form-group text-center" style="margin-top: 40px;">
<input type="submit" class="btn btn-success btn-block" value="Create Account">
</div>
<% end %>
Here is the JS:
#In <head> <script src="https://js.stripe.com/v3/"></script>
var stripe = Stripe('pk_test_sadnasd2n3krekl3k434kla');
var elements = stripe.elements();
var card = elements.create('card', { style:
{
base: {
lineHeight: '2'
}
}
});
// Add an instance of the card UI component into the `card-element` <div>
card.mount('#card-element');
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
function createToken() {
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the user if there was an error
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server
stripeTokenHandler(result.token);
}
});
};
// Create a token when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(e) {
e.preventDefault();
createToken();
});
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
Here is the controller:
class Users::RegistrationsController < Devise::RegistrationsController
def create
super do |resource|
if params[:plan]
resource.plan_id = params[:plan]
if resource.plan_id == "1"
resource.save_with_payment
else
resource.save
end
end
end
end
end
And here is the model:
class User < ApplicationRecord
attr_accessor :stripeToken
def save_with_payment
if valid?
customer = Stripe::Customer.create(description: plan_id, email: email, plan: plan_id, card: stripeToken)
self.stripe_customer_token = customer.id
save!
end
end
end
Can any one help with why the card is not linking with the customer when it is created?
stripe token should be passed in source attribute not in card.
it will work we are using this way and you can also refer to the API documentation it doesn't accept card attribute .
it accepts stripeToken as source in customer endpoint Refer