I think the way that Stripe handles Subscriptions and Customers has changed recently, where `Stripe::Subscriptions.create` no longer requires the source, but must be passed to `Stripe::Customers.create` instead. I'm having trouble creating the `stripe_customer` method because of this (since the token must be passed to where ever the Customer is being created. Any chance you code shed some insight on this?
I believe you're correct. Here's something similar to how I'm handling it now. I fetch the stripe customer, create a source from the token generated from stripe, set the source to the customer and then create a subscription on the customer with the plan and personally, I always pass in an idempotency key.
```
customer = current_user.stripe_customer
source = customer.sources.create({ source: token })
customer.default_source = source
customer.save
subscription = customer.subscriptions.create({ plan: plan }, { idempotency_key: unique_key })
```
Gotchya...thanks for the quick reply man! I'll rollback my custom `stripe_customer` approach to follow yours, creating a customer from the email, and try to create the `source` after as you outlined above.
Also, I like the idea of using an idempotent key, since we don't have the single-use guarantee that comes with a token generated by Stripe.js. Are you passing your idempotency key through the user's browser via the payment form and back into your controller? Not sure how to set this up exactly but I think it would help alleviate accidental double clicks along with any network hiccups
It's kind of strange how it works. The client browser side of things only communicates to the Stripe servers. The Stripe servers respond back with a token. In our javascript, we then add the token to the form parameters and then submit our form to the application. So, we would have something like a plan name and then the generated stripeToken which gets sent to our servers (never the credit card information!). From there, we will do the actual charge. The stripeToken is really just a "preauthorization" rather than a purchase. We then create the idempotent key.
So, if you were to have it all in the create action of the subscriptions controller, it would look something like this.
However, I would move out the logic for creating the stripe customer and the subscription into a service object.
The unique_key can really be anything that will be unique. In this case, you could generate a timestamp for the user as an epoch time in milliseconds.
```
def create
begin
customer = current_user.stripe_customer
source = customer.sources.create({ source: params[:stripeToken] })
customer.default_source = source
customer.save
subscription = customer.subscriptions.create({ plan: 'plus' }, { idempotency_key: unique_key })
current_user.update(stripe_subscription_id: subscription.id)
redirect_to root_path, notice: 'Thanks for subscribing!'
rescue Stripe::CardError => e
flash.alert = e.message
render action: :new
end
end
private
def unique_key
@unique_key ||= Rails.cache.fetch(['stripe', current_user], expires_in: 5.minutes) { (Time.now.to_f * 1000000).to_i.to_s }
end
```
☒ can you provide more context? It sounds like you're passing the name parameter into a Stripe call and it doesn't recognize that parameter. Is this when trying to create a Plan? If so, look at the show notes for an update to this as their API has changed.
I had the craziest time getting this to work. In the end, my element was just not showing (maybe browser extension problems -_-). If you only see a tiny grey box on your screen when you expect to see a credit card input box, try adding this to the .StripeElement in your subscription.css file:
☒ I prefer Stripe Checkout now since it handles a lot of things out of the box that you don't have to think about like the 3D Secure credit cards and any other security practices. I do have recent episodes on that topic.
However, if you still want to go this route, check your browser's dev console to see if there are any javascript errors on the page and let us know.
☒ The Stripe API 2020-08-27 and later no longer have the customer.subscriptions option by default. Instead to get the user's subscription you can do this.
In the stripe_customer method, You wouldn't need to search the subscriptions with customer: user.stripe_id since you're in the user model already. Just use stripe_id On the create action, You should create a Subscription and pass in the stripe customer id.
I'm not sure why the stripe_customer is nil. Are you getting any errors from the stripe_customer method in the user model. The guard clause that you have may be problematic as you're likely returning nil since the user has a stripe_id (assuming). If the stripe_id exists, but you're getting nil returned when looking up the customer, you may have some other kind of problem going on. Looking a bit closer at it. you're trying to return a subscription on the stripe_customer method. You should be retrieving the customer (https://stripe.com/docs/api/customers/create?lang=ruby and also see the retrieve customer section)
The second issue you'll run into is the customer.subscriptions. Once you do have a customer object, you'll get the undefined method subscriptions for the stripe customer. You'll need to look up the subscription based on the subscription_id. https://stripe.com/docs/api/subscriptions/retrieve?lang=ruby
Did you change your stripe_customer method to pull the customer instead of the subscription (i.e., return Stripe::Customer.retrieve(stripe_id) if stripe_id? )
to something like this. I haven't tested this, but this is likely the basic flow where you attach the source to the customer (i.e., the payment method) and then you create the subscription.
☒ I am really trying to help guide you without giving all of the answers because there is so much in learning to troubleshoot these issues. In your particular case, the Stripe::Source.create has a required parameter called type. Since it would be impossible (or improbable) for anyone to know what that means except for the Stripe developers, it's important to look at their provided documentation. In this case, the Stripe::Source.create points to this reference in the documentation. https://stripe.com/docs/api/sources/create#create_source-type Since they don't give much meaning to what the type parameter is as far as the available values, we need to look at the source object. https://stripe.com/docs/api/sources/object#source_object-type Since you're taking in credit cards, you would use the type "card"
☒ i am having this new error. I have look at the doc. the source on the API doc is different from the source on my app. Is that normal behaviour this is the source on my stripe
Their API within their Docs should be the latest ways of handling changes. Was this all from the same request? It's really strange that the source in the first image doesn't match the source ID from the byebug.
☒ No sorry, my mistake. I took the screenshot and made another request. The source from the byebug always matches that of the error. I really need help. I am stuck here. Any idea the reason for the error
With byebuy enabled, and once it gets triggered, head over to stripe to see if you can look up the source that was created before it is assigned to the customer.
And honestly, I would still really recommend checking out Stripe Checkout. It is so much easier to work with than the Payments API. I would only recommend the Payments API if you are dead set on having a single experience. And, personally, I have some assurance feeling knowing that I'm entering my card details on Stripe's website itself and not through the Payments API as I cannot always trust how a website is handling that information.
does this not work anymore? or is it still up to date? it keeps breaking for me on ```customer.subscriptions.create``` from the subscriptions controller
They may have changed the api again. I stopped using their Stripe Payments solution and prefer the Stripe Checkout. But, if this is the route you want to go. see this resource of their latest API docs. https://stripe.com/docs/api/subscriptions/create
So it now looks like this
Thanks for the lesson! Spot on, as always =)
However, if you still want to go this route, check your browser's dev console to see if there are any javascript errors on the page and let us know.
or
On the create action, You should create a Subscription and pass in the stripe customer id.
The second issue you'll run into is the customer.subscriptions. Once you do have a customer object, you'll get the undefined method subscriptions for the stripe customer. You'll need to look up the subscription based on the subscription_id. https://stripe.com/docs/api/subscriptions/retrieve?lang=ruby
Did you change your stripe_customer method to pull the customer instead of the subscription (i.e., return Stripe::Customer.retrieve(stripe_id) if stripe_id?
)
to something like this. I haven't tested this, but this is likely the basic flow where you attach the source to the customer (i.e., the payment method) and then you create the subscription.
This is what I use to create the Product/Plan
now this
Error
Since they don't give much meaning to what the type parameter is as far as the available values, we need to look at the source object. https://stripe.com/docs/api/sources/object#source_object-type
Since you're taking in credit cards, you would use the type "card"
So your code should look like
I am not positive, but I would avoid the card_present option as that is typically when the card is physically present when entering the details.
this is the source on my stripe
this is from byebug
I really need help. I am stuck here. Any idea the reason for the error