Some people constantly email me with questions about how build a structure for handle PayPal subscriptions on Rails apps, in this post series I’ll try to help you create that. I expect that you have a basic Rails knowledge because I’ll focus more on the app code design instead Rails basics.
You already can see the full app in this Github repository. Enjoy!
We’ll use the latest Rails version until now, the 4.1.X, we’ll also use the greatest @fnando’s rubygem paypal-recurring, this gem deals with all the PayPal API requests, which makes our life more easy. The gem’s link points to my fork because the original version doesn’t send the
reference field to the PayPal endpoints, which is necessary for our implementation.
In the persistence layer we’ll use this very simple database structure.
Notice the PayPal fields in subscription table (
paypal_profile_id), I’ll get to that later, still in this table we have the
canceled columns that I believe needs no explanation.
The plans table have the required
price column, which will precify the subscription, and a PayPal description, which is a column for a small and especific description for PayPal checkout page, this must be less or equal to 100 characters and can’t contains any special character, so, in our
Plan model will can override the paypal_description setter to always treat these description rules, like this:
The rest of schema basically deals with relations, subscription belongs to some plan.
The process in our app starts in the plans page, the user choose a plan and click in the subscribe button, clicking in this button we create the subscription record for this user and redirect him to the PayPal checkout page, returning from successuful subscription profile creation authorization we start the subscription charging, after that, in a especific endpoint of our app, the PayPal will sends to us notifications about the subscription situation and with these infos we’ll update the
paid_until column, which will indicates in our app whether the subscription is active or not.
In other part of our app the user will have a page with their subscriptions infos, including status (canceled/running/payment pending), and a button for cancels it, clicking in the cancel button our app will submit a subscription profile canceling request to the PayPal API, after some time, PayPal will send to our app a notification about the cancellation situation and we’ll toggle the
false value in the
canceled subscription column.
To maintain the organization of our flow we’ll split the whole subscription routine in four small and specialized objects. Below I’ll show these objects details involved in the process. In the next post I’ll show how to wire up everything.
For every PayPal request we need send options to identify for what subscription we are pretending make the action, for centralize the default options we’ll create a very simple object, with one class method only, this object will return the options based on the subscription record on the first function argument.
Note that our subscriptable entity needs respond to
price. The first four properties are columns of subscriptions table, the latter two are delegates to the associated plan entity, remember that.
Notice that we defined no trial period (
trial_length), and the charging period starting right now (
start_at), this way the subscription profile will makes the first charge.
Some tutorials and even the gem documentation recommends you to make one first express checkout and then create the recurring profile, but I highly don’t recomend this, because your express checkout payment can works fine, but your subscription profile creation can fails, in this situation you have a failed subscription profile but one charge in user account, which is very bad! Leaving the whole charging process to the subscription profile, if the subscription creation fails, the user won’t be charged.
This object will hide the specifics PayPal gem API (the gem interface, not the PayPal REST API) interactions on our app. With this object we’ll no longer need instanciate the gem object and each public class method express an action and returns the interested value of action, for exemple, the
checkout_url action method will returns the checkout url, with this we don’t need access the checkout_url property of PayPal gem object in other parts of our app and if the property name change only in this facade we will need change.
This object will take an action (cancelation or updates how long it’s paid) depends on notification received from PayPal on our PayPal notifications endpoint, note that this object will receive a subscription record and a notification object, this notification is an instance of
This object will be reponsible to get the PayPal recurring payment profile id (which will delegate to our
PaypalSubscription::ResourceFacade the profile creation on PayPal) and the payer id to save these informations on our subscription record.
In this first part we got how structure the app backbone, in the next post I’ll show how clue everything in the controller layer. If you have any question ping me on Twitter or leave your comment below.
See you soon.
— Edit —
Este post tem o "código aberto", caso encontre algo errado, desatualizado ou queira incorporar alguma coisa faça um pull request.