RailsApps / rails-stripe-membership-saas

An example Rails 4.2 app with Stripe and the Payola gem for a membership or subscription site.

Home Page:http://railsapps.github.io/rails-stripe-membership-saas

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

error when signing up users on production

macoughl opened this issue · comments

Hi Daniel,

Thank you for these tutorials. As a Rails newbie I've run through a lot of tutorials over the last few months and this has definitely been one of the most helpful.

About a month ago I successfully completed your tutorial as the base for a project I'm working on. I've been slowly customizing it and implementing your updates as you've added to the tutorial. It was working perfectly on my local machine and on production.

However, I am now experiencing an error on production (heroku) when signing up new users that I've spent days trying to fix and am now hoping you can maybe point me in the right direction.

The app works fine on my local machine. Admin works as it should and I can sign up new users as long as they have @gmail.com as their email address.
Due to the following in user.rb:

return if email.include?('@gmail.com') and not Rails.env.production?

On production, the admin works fine but after submitting the form for a new user, I land on the /users URL and see the error msg "We're Sorry But Something Went Wrong" in red.

After running heroku logs it looks like it gives me the RuntimeError (Stripe token not present. Can't create account.) and it references app/models/user.rg:51:in 'update_stripe' which I will paste now:

class User < ActiveRecord::Base
  rolify
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :stripe_token
  attr_accessor :stripe_token
  before_save :update_stripe
  before_destroy :cancel_subscription

  def update_plan(role)
    self.remove_role(self.roles.first.name)
    self.add_role(role.name)
    unless customer_id.nil?
      customer = Stripe::Customer.retrieve(customer_id)
      customer.update_subscription(:plan => role.name)
    end
  end
  
  def update_stripe
    return if email.include? (ENV['ADMIN_EMAIL'])
    return if email.include?('@gmail.com') and not Rails.env.production?
    if customer_id.nil?
      if !stripe_token.present?
        raise "Stripe token not present. Can't create account."
      end
      customer = Stripe::Customer.create(
        :email => email,
        :description => name,
        :card => stripe_token,
        :plan => roles.first.name
      )
    else
      customer = Stripe::Customer.retrieve(customer_id)
      if stripe_token.present?
        customer.card = stripe_token
      end
      customer.email = email
      customer.description = name
      customer.save
    end
    self.last_4_digits = customer.active_card.last4
    self.customer_id = customer.id
    self.stripe_token = nil
  rescue Stripe::StripeError => e
    logger.error e.message
    errors.add :base, "Unable to create your subscription. #{e.message}"
    stripe_token = nil
    false
  end
  
  def cancel_subscription
    unless customer_id.nil?
      customer = Stripe::Customer.retrieve(customer_id)
      if (!customer.nil?) && (customer.subscription.status == 'active')
        customer.cancel_subscription
      end
    end
  rescue Stripe::StripeError => e
    logger.error e.message
    errors.add :base, "Unable to cancel your subscription. #{e.message}"
    false
  end
  
  def expire
    UserMailer.expire_email(self).deliver
    destroy
  end
  
end

When I run heroku config it has all my live key variables and everything looks correct.

Any direction you can give me would greatly appreciated!

From your description, it sounds like the stripe token might not be getting passed back to the server. You can verify by checking your heroku logs. You should see something similar to where the "Parameters:" line includes the "stripe_token" attribute.
2013-01-24 05:16:19+00:00 app web.1 - - Started POST "/users" for n.n.n.n at 2013-01-24 05:16:19 +0000
2013-01-24 05:16:19+00:00 app web.1 - - Processing by RegistrationsController#create as HTML
2013-01-24 05:16:19+00:00 app web.1 - - Parameters: ...

If there is a value there for the token, then you are getting a token and probably have an issue with your RegistrationsController or User model. If there is no value, then take a look at app/assets/javascripts/registrations.js and app/views/devise/registrations/new.html.erb. Make sure that your form in new.html.erb has the class "card_form" that matches the jquery used in registrations.js. Also make sure there is a hidden field for the stripe_token in the form so the javascript can set it. Your new.html.erb page should also have your public stripe API key in a meta tag. You can verify this by viewing your heroku-hosted sign up page with Firefox and View Page Source (or use the excellent Firebug add-on).

Thanks for the response billvieux!

I see your first line in the logs but its not followed by either of the other two. The only time "Stripe Token" is referenced is in a few lines after the first one you said to look for and it is that runtime error I mentioned

RuntimeError (Stripe token not present.  Can't create account.)
app/models/user.rb:51:in 'update_stripe'

I've looked in the files you referenced and I believe I have everything as it should be. The only difference being that I do not have my public stripe key in a meta tag. That is fairly new to the tutorial and it used to set an ENV variable there, which was before the app used figaro and since I'm on a PC I just hard coded my pk_live Stripe key in. I have updated and added Figaro, have tried using the ENV variable there but currently have it hard coded. The proper variables are set in Heroku as I do use the ENV variables in my initializers/stripe.rb

registrations.js.erb

$('.registrations').ready(function() {
  $.externalScript('https://js.stripe.com/v1/').done(function(script, textStatus) {
      Stripe.setPublishableKey('pk_live_my-live-key-here');
      var subscription = {
        setupForm: function() {
          return $('.card_form').submit(function() {
            $('input[type=submit]').prop('disabled', true);
            if ($('#card_number').length) {
              subscription.processCard();
              return false;
            } else {
              return true;
            }
          });
        },
        processCard: function() {
          var card;
          card = {
            name: $('#user_name').val(),
            number: $('#card_number').val(),
            cvc: $('#card_code').val(),
            expMonth: $('#card_month').val(),
            expYear: $('#card_year').val()
          };
          return Stripe.createToken(card, subscription.handleStripeResponse);
        },
        handleStripeResponse: function(status, response) {
          if (status === 200) {
            $('#user_stripe_token').val(response.id)
            $('.card_form')[0].submit()
          } else {
            $('#stripe_error').text(response.error.message).show();
            return $('input[type=submit]').prop('disabled', false);
          }
        }
      };
      return subscription.setupForm();
  });
});

The line from new.html.erb utilizing the card_form class

<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => {:class => 'card_form form-vertical' }) do |f| %>

I forgot, I put
config.logger = Logger.new(STDOUT)
around line 40 of my config/environments/production.rb so I get a little more logging on the server-side.

You can also troubleshoot this from the client-side. I would recommend using Firefox. Under the web developer menu, open the web console. You should select the "Log Request and Response Bodies" option to capture network traffic. Then you can verify that your form is executing the javascript, calling stripe servers for token, and POSTing to your site with the token in the expected location in the form values.
screenshot

Thanks! I ran it as you described in Firefox and got the following:
inspect-top
inspect-bottom

No token. However, running signup/sign in on my local environment works just fine.

Outside the meta tag stripe key insertion, my files look the same as the tutorial.

So it is client-side issue. Verify that you see a call to the stripe api server before your POST to /users (see my screenshot). If that isn't there, look to see if there are any javascript errors in the console to point you in the right direction. You can also add console.log calls into your registrations.js to help trace the issue or attach a javascript debugger to the browser.

Not sure if you added any other gems to your application. I've been bitten before by not specifying the version number of a gem in my Gemfile. Locally I was running one version, but heroku had an updated version that behaved differently.

Fixed it!

Thank you for all the help! It was a javascript error I believe was caused by an bootstrap theme .js file.

I had removed the theme and the only calls to the .js file were on the homepage but I'm thinking that since the .js file was still in the /javascripts folder the asset pipeline was hitting it and causing an error.

Regardless, its working now. Thanks again!