Generating product recommendations in Spree using the Jaccard Index

Being able to recommend products to shoppers is a vital part of any online store. The “Customers Who Bought This Item Also Bought” section can lead to a lot of extra sales if done well. The Jaccard Index is a way of measuring similarity between items. Using some custom SQL we can extract the values we need:

With these values we can then calculate the affinity between sold products:

 

Naming service classes in Rails

One of the core ideas of Rails is convention over configurations. Models go in app/models, controllers go in app/controllers and views go in app/views. The danger is that we stick to those conventions no matter what and we end up either with fat controllers, fat models or even worse a mixture of both.

Many times we don’t take enough advantage of Ruby’s object oriented nature and the ability to extract functionality out into separate classes. Doing so can make an entire application easier to extend, understand and test. I have tried approaching this from different angles in different projects and I’ve found that the two main hurdles to getting this right are naming classes and putting them in the right place.

I have experimented with naming such as UserAuthenticator and UserAuthenticationService, and always end up feeling uncomfortable I constantly wonder if the other name is better or if there is a better way entirely. Using agent nouns in class names is considered a code smell, but the more that I think about it the important part is picking a choice and sticking to it. I was looking at the GitLab repository and noticed that they’ve done exactly that, everything is named in a consistent manner. I think many may dislike that but it makes things extremely clear and easier for anyone contributing as to what they should name their classes and where they should put them.

Adding a custom Spree payment Gateway outside a Rails Engine

Adding a new Payment Gateway to Spree through a Rails Engine is pretty straight forward as you can hook in your new gateway after the initial payment gateway array has been created. This is how the spree_gateway gem does it:

If you want to do the same thing for your own project contained gateway it’s a little different. If you try to just directly edit the payment_methods array in an initializer it will get wiped out when the Spree core engine sets the initial bogus and simple methods. I got around the problem by hooking my gateway in using the after_initialize method. Here I’m hooking in after SpreeGateway:

Rspec + Devise user and current_user different

If you follow the Devise Wiki on setting up Rspec and Devise you may end up wanting to set an expecatation on the currently signed in user.

Don’t fall into the trap of setting it on the original user model as your specs will still fail:

user.should_receive(:blah).once # Won't work

Rather, you should set it on the controller’s current_user:

subject.current_user.should_receive(:blah).once # Will work!

Devise Omniauth Dynamic Providers

My current project www.viewshound.com requires different users to have different scopes for their Facebook authentication. Warden supports dynamic providers out of the box. To get it working with Devise was pretty easy, just a couple of minor changes were needed especially to support Facebook.

First up was creating the new route. As I’m using a controller called Omniauth and not Session, the :to attribute is different. The other thing to note is I’m matching /users/auth/facebook/setup, not /auth/facebook/setup like in the Warden documentation.

routes.rb

Next we create the new setup action for Warden to call. The docs use consumer_key and consumer_secret, but facebook expects client_id and client_secret, so be sure to use those instead. This is where I make changes to the scope based on the current user if they are signed in or not. So a user can re-authenticate with Facebook to get more permissions for their account if they wish.

omniauth_controller.rb

Finally change the devise.rb initializer to support the new setup.

devise.rb

Restart your application and you should be good to go.

Paperclip S3 expiring_url with styles and SSL

A current requirement is that assets uploaded to Amazon S3 must be accessed via SSL and use an expiring URL. Using an expiring url with Paperclip is extremely easy.

The problem is expiring_url doesn’t let you choose a style and doesn’t use https, which breaks our SSL site. To add the behaviour was an easy “hack”. I added the file /config/initializers/paperclip.rb with the following code:

Now calling my expiring image URL with a style and over https is just:

Rspec/Cucumber Autotest Loop

Autotest would constantly run my tests even though I hadn’t modified anything. Which made it impossible to actually use. Creating the following in a file called .autotest in my application’s root solved the problem for me. This is on Rails 3 RC, RSpec 2 beta 19 and Cucumber 0.8.5.

Thoughtbot Clearance & mongomapper

Having a play with mongomapper and wanted to get Clearance working with it. Seemed to just be a simple case of doing the following in my user model.

My full user model ended up looking like this:

Perhaps if I have time, I will look into adding attr_accessible support to mongomapper myself.

Update 13/03/2010: I believe the dependency on attr_accessible in clearance has since been removed. So this small hack is most probably defunct.

Law of Demeter and the delegate method

The Law of Demeter, or Principle of Least Knowledge is a fairly simple design pattern, which, simply put means that an object should only talk to it’s immediate “friends”

The law states that a method M of and object O may only invoke the methods of the following kind:

1. a method on O itself
2. any parameters passed to M
3. any objects instantiated within M
4. any direct components of O

The classic example coined by David Bock used a Paperboy (one object) delivering a paper, then extracting money from a Customer’s (another object) Wallet (and another):

In the “real world” the Paperboy would ask the customer for the money who would then take it out for them, rather then the Paperboy reaching into the customer’s back pocket and getting it for themself.

Really we want something as follows:

This may all seem trivial and a waste of time, but what happens if some Customers want to pay by cheque? Those decisions should have an impact on the Paperboy, otherwise we end up with:

Where as it makes more sense for the change to be contained within the Customer:

So what does this have to do with Rails and the delegate method? The delegate method adds a quick and simple way of following the Law of Demeter without having to do very much at all.

This setup means to get an Order’s payment we would have to say:

But if we simply change our objects as such:

Now all we have to say is:

So at any time, the details of how a payment  is to be decided can be contained with the Customer. This is of course a simplistic example, but hopefully explains how you chould be using this handy feature.

rake spec fixtures failing

For some reason my rspec fixtures were not loading into my development database when doing spec:db:fixtures:load. An extra parameter to db:fixtures:load is all that’s needed.

Fixed by: