Ernesto Rivas
Ernesto Rivas

Reputation: 41

Stripe::InvalidRequestError in Users::RegistrationsController#create

I'm not getting any errors anymore, but I know that when I create a new user the stripeToken doesn't get written.

controllers/users/registrations_controller.rb

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

models/user.rb

class Users < ActiveRecord::Base

devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable
belongs_to :plan
attr_accessor :stripeToken

    def payment
    if valid?
      customer = Stripe::Customer.create(
          description: email,
          plan: plan_id,
          card: stripeToken
      )
      self.stripeToken = customer.id
      save!
    end
  end
 end

assets/javascript/users.js

$(document).ready(function() {
   Stripe.setPublishableKey($('meta[name="stripe-key"]').attr("content"));
    // Watch for a form submission
    $("#form-submit-btn").click(function(event) {
        event.preventDefault();
        $("input[type=submit]").prop("disabled", true);
        var error = false;
        var ccNum = $("#card_number").val(),
            cvcNum = $("#card_code").val(),
            expMonth = $("#card_month").val(),
            expYear = $("#card_year").val();

        if (!error) {
            // Get the Stripe token:
            Stripe.createToken({
                number: ccNum,
                cvc: cvcNum,
                exp_month: expMonth,
                exp_year: expYear
            }, stripeResponseHandler);
        }
        return false;
    }); // form submission

    function stripeResponseHandler(status, response) {
        // Get a reference to the form:
        var f = $("#new_user");

        // Get the token from the response:
        var token = response.id;

        // Add the token to the form:
        f.append('<input type="hidden" name="user[stripe_card_token]" value="' + token + '" />');

        // Submit the form:
        f.get(0).submit();
    }
});

views/layouts/application.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>tinito</title>
  <%= stylesheet_link_tag    "application", media: "all" %>
  <%= javascript_include_tag "https://js.stripe.com/v2/", type: "text/javascript"  %>
  <%= javascript_include_tag "application" %>
  <%= tag :meta, name: "stripe_api_key", content: STRIPE_PUBLISHABLE_KEY  %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= render "layouts/header" %>

<% flash.each do |key, value| %>
    <%= content_tag :div, value, class: "alert alert-#{key}" %>
<% end %>
    <%= yield %>
<%= render "layouts/footer" %>

</body>
</html>

views/devise/registrations/_pro_form.html.erb

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) 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, placeholder: "Email", class: "form-control" %>
    </div>

    <div class="field form-group">
      <%= f.label :password %>
      <% if @minimum_password_length %>
          <em>(<%= @minimum_password_length %> characters minimum)</em>
      <% end %><br />
      <%= f.password_field :password, autocomplete: "off", placeholder: "Password", class: "form-control" %>
    </div>

    <div class="field form-group">
      <%= f.label :password_confirmation %><br />
      <%= f.password_field :password_confirmation, autocomplete: "off", placeholder: "Confirm Password", class: "form-control" %>
    </div>

    <div class="form-group">
      <%= label_tag :card_number, "Credit Card Number" %>
      <%= text_field_tag :card_code, nil, name: nil, placeholder: "41*****", class: "form-control" %>
    </div>

    <div class="form-group">
      <%= label_tag :card_code, "Security Code on Card (CVV)" %>
      <%= text_field_tag :card_number, nil, name: nil, placeholder: "123", class: "form-control" %>
    </div>

    <div class="form-group">
      <%= label_tag :card_month, "Card Expiration" %>
      <%= select_month nil, {add_month_number: true},{name: nil, id: "card_month"} %>
      <%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
    </div>

    <div class="actions form-group">
      <%= f.submit "Sign up", class: "btn btn-primary", id: "form-submit-btn" %>
    </div>
<% end %>

controllers/application_controller.rb

 class ApplicationController < ActionController::Base
   protect_from_forgery with: :exception



    before_filter :configure_permitted_parameters, if: :devise_controller?

      protected

      def configure_permitted_parameters
        devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :stripeToken, :email, :password, :password_confirmation) }
      end
    end

db/migrate/*****_add_stripe_token_to_users.rb

class AddStripeTokenToUsers < ActiveRecord::Migration
 def change
    add_column :users, :stripeToken, :string
  end
end

Upvotes: 2

Views: 686

Answers (3)

Jon Lambson
Jon Lambson

Reputation: 510

Add an ID to your form_for in: views/devise/registrations/_pro_form.html.erb

<%= form_for(resource, as: resource_name, :html => {:id => "payment-form"}, url: registration_path(resource_name)) do |f| %>

also add

<div class="payment-errors text-danger"></div>

this will display your error responses from Stripe. Update User.js to handle error responses as @vivrass mentioned.

$(document).ready(function() {
  Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
  // Watch for a form submission:
  $("#form-submit-btn").click(function(event) {
    event.preventDefault();
    $('input[type=submit]').prop('disabled', true);
    var error = false;
    var ccNum = $('#card_number').val(),
        cvcNum = $('#card_code').val(),
        expMonth = $('#card_month').val(),
        expYear = $('#card_year').val();
    if (!error) {
      // Get the Stripe token:
      Stripe.createToken({
        number: ccNum,
        cvc: cvcNum,
        exp_month: expMonth,
        exp_year: expYear
      }, stripeResponseHandler);
    }
    return false;
  }); // form submission
  function stripeResponseHandler(status, response) {
    var $form = $('#payment-form');

    if (response.error) {
      // Show the errors on the form
      $form.find('.payment-errors').text(response.error.message);
      $form.find('button').prop('disabled', false);
    } else {
      // response contains id and card, which contains additional card details
      var token = response.id;
      // Insert the token into the form so it gets submitted to the server
      $form.append($('<input type="hidden" name="stripeToken" />').val(token));
      // and submit
      $form.get(0).submit();
    }
  };
});

Lastly... You are most likely testing with an old card. If you are using the card number 41111111111111111 cvv123, you will receive an error response from Stripe stating, "Your card number is incorrect."

Use an update testing card found here: https://stripe.com/docs/testing

Upvotes: 2

vivrass
vivrass

Reputation: 1

You problem is probably in Javascript on the line "var token = response.id;". Did you verify the Stripe response you receive?

The Stripe documentation verify if there was an error with the Stripe request which you are missing in your implementation (https://stripe.com/docs/tutorials/forms)

function stripeResponseHandler(status, response) {
  var $form = $('#payment-form');

  if (response.error) {
    // Show the errors on the form
    $form.find('.payment-errors').text(response.error.message);
    $form.find('button').prop('disabled', false);
  } else {
    // response contains id and card, which contains additional card details
    var token = response.id;
    // Insert the token into the form so it gets submitted to the server
    $form.append($('<input type="hidden" name="stripeToken" />').val(token));
    // and submit
    $form.get(0).submit();
  }
};

Upvotes: 0

Arunkumar L
Arunkumar L

Reputation: 11

Did you try checking the rails logs on form submission whether the stripe token is passed as params?

May be it is filtered out because you did not include it in Strong Params.

Upvotes: 0

Related Questions