You wrote an awesome blog post. You've enabled comments for this awesome blog post, only to find that some crappy spam turnkey operation has hit your post with 1000 cialis ads, and the other wang pill advertisements.
Listen, Comment Spam sucks ass. If you've ever searched for an answer to stopping it, your research points you to one of four ways to stop comment spam traditionally. These are:
- No comment spam filters at all - Users are allowed to comment willy nilly.
- Captchas - weird images that look as though your seeing through beer goggles, whose text usually has to be written into a text field to prove your comment is coming from a human.
- Site Members can comment only - the site's membership, of which you are visiting, are only allowed to comment on stories. I am using that method in my blog, atm.
- Moderated comments - your honest feedback about a post can only be posted, if a nameless/faceless drone 'approves' your comment worthy of being posted. Doesn't say much for transparency.
While all of these above methods work to keep spam to a minimum, (and really that's all you can hope for i.e., minimal spam), there are glaring flaws in each and everyone one of the above methods. Whether it's accessibility, too cumbersome to keep up with, or too communist, most of these methods have some kind of tradeoff.
Enter Acts_as_snook
From the README:
The acts_as_snook plugin is a great way to keep spam at a minimum. Rather then asking the user to do anything, acts_as_snook "scores" each comment based on a scoring system by Jonathon Snook. Once the comment has been saved into the database, the comment receives one of three possible spam statuses:
- Spam - the comment didn't pass the scoring system and will have a status of spam, set in the database.
- Ham - the comment passes the scoring system and it's status is set to ham in the db.
- Moderate - the comment is too close to call spam or ham, so it's status is set to moderate and is awaiting moderation.
About the Plugin
If anyone trolls in #rubyonrails, the IRC chatroom, you'll know the author of the acts_as_snook plugin, rsl.
He is also responsible for getting this song in my head, at the time of writing. Bastard.
Tutorial - How to use the Plugin
Don't cut and paste!!! this stupid blogger crap is garbage! So if you want to cut and paste, you'll need to delete the spaces after and before each < or > bracket.
Assumptions - you know how to create a typical blog application that will use embedded comments at the end of each post. I'm assuming that you will have two models Post andComment. Before you begin, get a working Post model ready, as this tutorial is only about adding a Comment model that uses acts_as_snook. Lastly, you'll want to make it prettier once your done these steps, so that is up to you do after, post modem.
You have a working Post model, right???
Get your Post model working how you want it to work. The inner workings aren't important for this tutorial.
Generate a Comments Model and a Post Migration
We'll use the default settings in acts_as_snook, so that means we need our database to house these Comments table columns as outlined below.
script/generate rspec_scaffold Comment author:string email:string url:string body:text spam_status:string post_id:integer
Since we want to display how many GOOD comments we have (i.e, the ham), acts_as_snook will run a counter cache for each Post's ham comments. All you have to create the following migration file and add the migration column information to it:
script/generate migration AddHamCountToPost
In your new migration file add the following:
class AddHamCountToPost < ActiveRecord::Migration
def self.up
add_column :posts, :ham_comments_count, :integer, :default => 0
end
def self.down
remove_column :posts, :ham_comments_count
end
end
Run Migration with
rake db:migrate
Add Acts_as_Snook functionality
First make sure Post has_many Comments and Comments belongs_to Post.
Next add this to your Comment.rb file
acts_as_snook
Damn, that was easy.
Fix the Comment views
Right now, your views are set to show all comments, that is not good. Let's make your views shine! So in your Post#show view, here is what i've done (since i show my comments at the end of each blog post, my @comments= @post.comments. If you don't understand that, read up on associations in the rails guide). I'll explain the code further afterwards.
< h1 >Comments< / h1 >
< % unless @comments.blank? %>
< % @comments.ham.each do |comment| %>
< p >
< % if comment.url.blank? %>
< %= comment.author %>
< % else %>
< %= link_to comment.author, comment.url %>
< % end %>
says:< br/ >
< %= comment.body %>< /p>
< % end %>
< % else %>
< p>Be the first person to comment!< /p>
< % end %>
Simply put, we only want to show the ham(the good comments) and not the spam(shitty comments). So we iterate through each ham comment, using the acts_as_snook supplied method ham.
The rest of this code, just shows the comment in a certain way that i wanted it to appear, your mileage will vary.
Showing a Comment Count
One last little touch, is showing your readers how many comments each post has. I put this information on the Post#index page, usually. Here's one way you can implement a count for all ham comments.
< % @posts.each do |post| % >
< h2 >< %= link_to post.title, post % > ::~ < %= pluralize post.ham_comments_count, "Comment" % >< /h2 >
< p >< %= truncate post.body, 25 % >< /p >
< % end % >Notice again, we iterate through the posts and for each post, we add their ham_comments_count.
Conclusion
Acts_as_snook gives us a lot of easy to use methods, which i'll write more about in Acts_as_Snook part 2, which will include a moderation area for administrators. Hopefully Acts_as_snook will take care of your comment spam nightmares, while giving you more time to sing, same as it ever was. Letting the days go by....