Blocking Spam in Rails Applications
Ben Scofield, Former Viget
Article Category:
Posted on
Whenever you accept user-generated content, you run the risk of opening your system up to spammers. This is most well-known as a problem for blogs that allow comments; but, every relatively open site faces this challenge. There are many potential solutions to this problem -- you could write your own Bayesian filter, manually delete and blacklist IPs, or rely on an external service, for instance. For speed of development and ease of use, making use of an external service is by far the best way to go. For this post, we're going to take a quick look at Akismet.
About Akismet
Akismet was developed by the good folks at Wordpress to deal with comment spam. It is a web service that uses a variety of strategies to classify submitted content as spam or not. It's easy to set up and is (in our experience) very reliable. A variety of key types are available, including both commerical and free.Installation
The first step in getting Akismet working with your Rails app is to sign up for an API key (information on commerical keys can be found here). After getting your key, you'll need to download the Ruby API for Akismet and save it in your applications lib folder.Catching Spam
Once you've got your key and the Akismet class installed, you're ready to start catching some spam. To use a consistent example for the rest of this post, let's say you're writing a blog application and you want to check for and prohibit spam in comments. The most direct approach would be this:class Comment :create do |record, attr, value| allow_comment = false akismet = Akismet.new([YOUR API KEY], [THE URL FOR YOUR SITE]) unless akismet.verifyAPIKey record.errors.add attr, 'could not be validated - your API key is incorrect' else allow_comment = akismet.commentCheck( record.author.ip_address, record.author.user_agent, record.author.referrer, record.post.permalink, 'comment', record.author.full_name, record.author.email, record.author.url, value, {} ) unless allow_comment record.errors.add attr, 'appears to be spam' end end allow_comment end endObviously, this code makes certain assumptions about data contained in the Post and Author models (namely, that a fair amount of environment data is stored in this comment's author object, and that the post to which this comment will be attached has some permalink method). Nevertheless, this is a quick and easy approach that works well and can be easily modified to fit other situations.