RailsApps / rails-stripe-membership-saas

An example Rails 4.2 app with Stripe and the Payola gem for a membership or subscription site.
http://railsapps.github.io/rails-stripe-membership-saas
1.14k stars 232 forks source link

Stripe webhook fails when user has already been deleted #42

Closed PendragonDevelopment closed 11 years ago

PendragonDevelopment commented 11 years ago

I followed the tutorial closely, only changing body copy, but for some reason I'm receiving this error on the webhook when I delete an account:

Started POST "/stripe" for 50.18.189.119 at 2012-12-13 20:01:44 -0500 Processing by StripeEvent::WebhookController#event as XML Parameters: {"type"=>"customer.subscription.deleted", "object"=>"event", "created"=>1355446903, "livemode"=>false, "id"=>"evt_0uc5SPOrprKF4H", "pending_webhooks"=>2, "data"=>{"ob ject"=>{"status"=>"canceled", "trial_end"=>nil, "ended_at"=>1355446903, "start"=>1355446884, "cancel_at_period_end"=>false, "customer"=>"cus_0uc5pHMcIr7Qfy", "object"=>"subscriptio n", "current_period_start"=>1355446884, "plan"=>{"trial_period_days"=>nil, "interval_count"=>1, "amount"=>1499, "object"=>"plan", "currency"=>"usd", "name"=>"Platinum", "id"=>"plat inum", "interval"=>"month", "livemode"=>false}, "current_period_end"=>1358125284, "quantity"=>1, "canceled_at"=>1355446903, "trial_start"=>nil}}, "webhook"=>{"type"=>"customer.subs cription.deleted", "object"=>"event", "created"=>1355446903, "livemode"=>false, "id"=>"evt_0uc5SPOrprKF4H", "pendingwebhooks"=>2, "data"=>{"object"=>{"status"=>"canceled", "trial end"=>nil, "ended_at"=>1355446903, "start"=>1355446884, "cancel_at_period_end"=>false, "customer"=>"cus_0uc5pHMcIr7Qfy", "object"=>"subscription", "current_period_start"=>135544688 4, "plan"=>{"trial_period_days"=>nil, "interval_count"=>1, "amount"=>1499, "object"=>"plan", "currency"=>"usd", "name"=>"Platinum", "id"=>"platinum", "interval"=>"month", "livemode "=>false}, "current_period_end"=>1358125284, "quantity"=>1, "canceled_at"=>1355446903, "trial_start"=>nil}}}} ←[1m←[36mUser Load (0.0ms)←[0m ←[1mSELECT "users".* FROM "users" WHERE "users"."customer_id" = 'cus_0uc5pHMcIr7Qfy' LIMIT 1←[0m Completed 500 Internal Server Error in 2630ms

NoMethodError (undefined method expire' for nil:NilClass): config/initializers/stripe.rb:7:inblock (2 levels) in <top (required)>'

Rendered c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/_trace.erb (3.0ms) Rendered c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (3.9ms) Rendered c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (42.0ms)

Any thoughts on what might be causing the issue?

Repo Link: https://github.com/PendragonDevelopment/orion

DanielKehoe commented 11 years ago

See line 7 in the file config/initializers/stripe.rb. Looks like it can't find the find the user by customer id. You've got a customer id "cus_0uc5pHMcIr7Qfy" according to Stripe. Does that customer exist in your database?

PendragonDevelopment commented 11 years ago

On Stripe, or in the application? I do in Stripe, but not in the app (which would make sense, since I just deleted that user/customer).

Is it deleting the customer before it can send the email?

DanielKehoe commented 11 years ago

I'm confused. You've got the app deployed and you've set the webhook URL in your Stripe dashboard?

If the customer is in your database and you go to Stripe to trigger a webhook, the webhook request should send an "expire" email and delete the user from your database.

If you've already deleted the user before going to Stripe to trigger a webhook, the customer is gone from your database and the webhook request will fail and won't be able to send an "expire" email message.

PendragonDevelopment commented 11 years ago

Sorry I'm not explaining well. I have the app deployed on Heroku (http://skillum-orion.herokuapp.com) and everything else works fine. I can create users, they create customers and subscriptions on Stripe, and then when I go to cancel the account on the /users/edit page, it deletes the user, customer, and subscription. It calls the webhook but Stripe gets a 500 error and it never sends the email.

DanielKehoe commented 11 years ago

Thanks for the clarification. This is a genuine bug. Personally, I never deployed it with webhooks enabled so I haven't seen this before.

You are deleting the user in the application and Stripe gets informed and then Stripe fires a webhook. The webhook fails because the user is already deleted. I assume you see a flash message that you've successfully deleted the user? Is that right? And the only evidence that the webhook fails is the log message? There would be nothing in the browser since it is a webhook request.

I never intended the "expire" message to be sent when the admin cancels an account. As far as I'm concerned, that's a detail for you to implement. My only intent with the "expire" message was to demonstrate that something could be done in response to webhook triggered by a "card is declined on rebilling" event.

So I believe the implementation is functioning as I intended. I should trap the error triggered by the webhook in this case so we don't have error messages in the log file. But I never intended for the "expire" message to be sent in the use case you describe.

As to whether the implementation is appropriate for the use case, that is another matter and open for discussion (and patches).

PendragonDevelopment commented 11 years ago

Ah, okay then. I only noticed it because I was expecting an email, and didn't receive one. I would assume that more configuration of ActionMailer and a transactional email service would be needed for that, yes?

DanielKehoe commented 11 years ago

Okay and thanks for bringing the bug to my attention. I'll put in on my list to be fixed.

You're right, to send emails for various lifecycle events, you can add an ActionMailer similar to the one that's there for the "card is declined on rebilling" event. And as you mention, I'd urge you to use the Mandrill (or competitors) API instead of ActionMailer. That'd make for a nice Tutorial Part Two topic.

PendragonDevelopment commented 11 years ago

That's functionality I'm looking for, so perhaps I'll do a clean fork and set it up. If I get it working, I'll submit a pull request though fair warning, I'm pretty horrible at writing good tests.