At work, I was recently tasked with building a web site wrapper around a Heroku software-as-a-service that we had built earlier last year (Bomberman). While the core functionality of this new application is identical to the Heroku service, we were required to implement our own subscription service to replicate the purchasing and billing functionality provided by Heroku and throughout the course of the project we have used several interesting technologies and encountered a few strange issues which will be discussed here.
There are many open source libraries (gems using Ruby terminology) that are freely available for Rails which can drastically reduce the amount of code that needs to be written and tested. Of course, leveraging these would save us a great deal of time and effort and hence, we used the Spree e-commerce gem as the base for our subscription service. Spree is essentially an online store in a box and it makes setting up a basic e-commerce site quick and easy. However, Spree does not support subscriptions by default and we decided to use the spree-subscribe plug-in to add that functionality to Spree. These gems provided the base functionality that we desired, but we needed to make a few tweaks to make them fully match our needs. Fortunately, these tweaks can be easily made using one of two methods.
For changes in the Ruby code, all you need to do is add a decorator to the class or module that you want to modify. This can be accomplished by calling class_eval or module_eval method on the class or module that you want to modify and passing your changes in the block. This can be used to both add new functionality and modifying existing functionality as the code you have in your decorator will take precedence. This does mean that modifying an existing method is an all or nothing affair which is slightly annoying when you want to keep most of the original functionality of the method as you have to copy the original code for that method. Nonetheless, it is still a great way to modify specific pieces of an existing library’s code to fit your exact needs.
To modify Rails views, we can use the Deface gem that automatically comes with Spree to override specific parts of each view. Deface overrides are designated using the .deface extension and are placed in a view specific subdirectory of the app/overrides directory of the Rails project. For example, we wanted to override a part of the spree/users/show.html.erb view, we would make an app/overrides/spree/users/show directory and place our deface files there. We can choose the name of these deface files which allows us to clearly document what each override is doing with just the name alone. For instance, if I wanted to replace the submit button of a form, I could name the file replace_submit_button.html.erb.deface to make the purpose of the override very obvious. The deface file itself is also rather simple with just two components. The first component is an HTML comment that describes the particular action that the override should do (i.e. insert_before / insert_after, remove, replace, surround, etc.) and a string containing CSS selector describing which element(s) that this change should be applied to. The second component is the actual content that will be used. The content can be in any format that you would otherwise use in a Rails view so using embedded Ruby code is fair game. This makes Deface perfect for modifying small portions of views such as adding / removing buttons or modifying pieces of text. Yet, for large changes, it is still recommended to override the whole view by placing your own view in your app/views folder.
Despite using these two techniques, I still found myself digging through the Spree source code quite a bit. The problem is that in order to modify a section of code, you must know what it does first and the best way to do that is through the source code. As a result, I probably spent more time reading source code than writing it. Nevertheless, this was quite beneficial to me as it not only helped me figure out what I needed to do, but it was also very educational. Reading through the source code exposed me to useful coding patterns that I would have never thought of such as the decorator pattern described earlier. Furthermore, looking through the source code exposed me to the other libraries that are used within Spree gem, such as state_machine and Active Merchant, which I can leverage in future projects. Hence, I found my time spent reading through the Spree source code to be very valuable and I would encourage others to look through the open source code that they are using given that they have the time.
While using Spree took care of a large chunk of the base functionality, we did encounter a couple of issues. The first issue was a result of a design problem in the spree-subscribe gem that we used. When I chose the spree-subscribe gem I naïvely assumed that it would work with our PayPal payment gateway out of the box. However, this was not the case and we soon discovered that the recurring payments were failing during our testing. The problem was that the spree-subscribe gem handled recurring payments by creating a new charge with the credit card used during the initial purchase as designated by a credit card profile. While this is fine for gateways that support credit card profiles, the PayPal gateway does not support profiles and our recurring payments were sending blank credit card numbers which is obviously invalid. Instead, it returns a reference code that can be used in place of the credit card information and we were able to fix the issue by modifying the recurring payment code to send this reference code instead of a credit card number. Nonetheless, this problem illustrated just how important integration testing is as you cannot just assume that third-party libraries will work with your situation and it is entirely possible that you could stumble upon previously undiscovered flaws in the third-party code.
A second, albeit minor, issue occurred when we were testing the integration of our payment system with a live PayPal account. In these tests, we tried sending one of the test PayPal credit card numbers to ensure that we received a reasonable response from the PayPal server (if it rejected them as invalid that would have been fine since they are not real credit cards), but our requests were constantly timing out and we would receive cryptic internal error messages from PayPal with no other details. We tried tweaking the configuration on both Bomberman and PayPal to no avail until we decided to just revert back our original settings and use one of the other credit card numbers. Just like magic this worked and we got the expected invalid credit card number message. Apparently, the credit card number we were using, 4111111111111111, was the problem and we were properly configured the whole time! Hence, you should never use the number 4111111111111111 to test against a live PayPal account, even if you are just checking to see if you are hitting the PayPal server correctly, as it does not seem to work on the PayPal side.
All in all, working with Spree was a great learning experience. Over the course of the project I not only learned what makes the popular e-commerce library tick, but I also learned about various other libraries that I can integrate into my future projects as I see fit. Furthermore, debugging the issues encountered with our payment system resulted in some interesting findings concerning PayPal and their API services. Nonetheless, I feel that Spree is a very solid base for any online store and I would definitely say that my experience with it so far has been a rather pleasant one.