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.
☒ in the subscriptions_controller.rb you can create a method to look up the plan. Something like
def selected_plan
plan = Plan.find(params[:plan])
plan.plan_code
end
And plan_code would be pro, annual, or whatever else that matches the plan ID within Stripe.
Then in the controller action, you would reference this selected_plan method in place of where 'pro' is in the episode.
Since Stripe has the list of plans, you need to have some awareness of what these plan ids are. Typically they will be fairly static within your application. So, you could set a global variable with an array of the plans. Something like
And wherever you need to loop over your available plans, then you can reference this global variable. This does limit you to having to deploy and make code changes for any new plans, but that could be a non-issue.
☒ I believe the main benefits of Stimulus is isolation, reloading, minimization, and ease of use.
Isolation - The controllers don't leak over into other pages. If the data attributes are present for that controller, it will work, but is deconstructed after the page refreshes or navigates away where those data attributes are no longer present. This makes working with complex front ends really nice. There is a caveat though with something like getusermedia where the use of a webcam or audio source could leak from one page to another and must be handled properly.
Reloading - Whether you're loading the controller on a new page refresh, adding in controllers via UJS, or even rending a partial sent over websockets, the controller will initialize and work. This use to be a pain in situations where UJS wouldn't initialize a datepicker and you had to manually initialize it again.
Minimization - You get a lot of functionality from such a tiny library. Even then, you don't have to write a bunch of Javascript to get highly interactive front ends. This combined with Turbolinks/Turbo makes for a super powerful tool.
Ease of Use - By following the conventions, you can make your javascript more readable and easier to maintain. Write less javascript and get more functionality. Bringing in additional libraries is easy with webpacker. This will be interesting to see how things change if we revert back to sprockets, but for now, webpacker is a very viable solution.
I recommend that you check out some of the other videos like Google Maps API, Video Chat with WebRTC, FullCalendar, AutoComplete, Drag and Drop, Audio Recording, QR Codes and Cropping images. All of these are accomplished using StimulusJS.
☒ You want to be careful with your plan_type. You are accepting the user input. They could type anything in the plan parameter and cause problems in your app. The PLAN array is just a list of the plans that you have created over in Stripe. If the plan_type doesn't find a matching plan, you should catch that and redirect the user.
In this episode, we update the user's attribute subscription_id. So, you could check this subscription_id if the user is subscribed.
def subscribed?
subscription_id.present?
end
You would of course need to handle the subscription cancelled in a similar fashion via the webhooks and clear the subscription_id.
I think that there is a follow up episode warranted to explore handling webhooks more. For example, on Drifting Ruby, we handle a few different events.
When the user subscription is successful
When a subscribed user is charged
When a subscribed user payment fails
When a subscribed user cancels
The last two are the trickiest. If a user payment fails, what should happen? This basically means that they have a subscription, but are not current with their payments. On Drifting Ruby, they still have their subscription where they can update their credit card information, but have been locked out of viewing the Pro Videos.
When a user cancels their subscription, no refund is given, but the subscription_id is also not removed. Instead, the expires_at attribute is updated to the end of their billing cycle which then will remove their subscription and access to the Pro videos.
In those kinds of situations, you have a few different paths.
If you use button_to for the button with remote: true, you can make an AJAX call via RailsUJS to your Rails application which would be a JS format. Within the <action>.js.erb, you could render a partial and insert it onto the page. If that partial has a stimulus controller within it, the controller would initialize and "just work"
If you use a stimulus controller for the button, when clicked, you can make the AJAX request back to the Rails application in a similar fashion and then render a partial within the Rails controller action and then insert this into the page.