Announcing Fu-fu: The Profanity Filter for Rails
That’s the most foul, cruel, and bad-tempered word you ever set eyes on!
Look, that word’s got a vicious streak a mile wide! It’s a killer!
There will be no killer words in this application: Behold the mighty Fu-fu! And there was much rejoicing… But first, a little history on Fu-fu: The Profanity Filter for Rails.
A Little History
Recently, I needed a simple (profanity/cuss/swear/bad word) filter for a Rails app, so I hit up Google for the answer as this seemed like a problem that should have been solved by an expert. Sadly, this was not the case.
Over the next day or so I was able to get a simple prototype up and running in our application and that’s the way it stayed for the next couple weeks. Then I realized that this was reason I wasn’t able to find a profanity filter plugin on Google.
Upon closer inspection it seems that people are building their own filters and leaving it at that. Almost being guilty of this, I decided that it was time to give back to the community and get a profanity filter plugin out in the wild.
I was able to publish the first version of the Profanity Filter during the Community Code Drive at RailsConf 2008. Hacking in the same room as DHH, David Chelimsky, Chad Fowler, Rich Kilmer, Marcel Molina Jr., and the entire Intridea team is a great motivator.
During RailsConf we decided that the plugin needed a real name; “Profanity Filter” wasn’t cutting it. Someone suggested fu-fu pronounced ‘eff-you-foo’. That was promptly shortened to ‘foo-foo’. How can you not love something named Fu-fu that deals with profanity and abuses plugin idioms at the same time?
Continue Rejoicing (Examples!)
The interface for Fu-fu is clean and straight forward. For example. lets say that ‘frak’ is a common curse word.
class Post < ActiveRecord::Base
profanity_filter :title, :body
end
post = Post.create(:title => 'Fraking title', :body => 'What a bunch of frak')
post.title #=> '@#$% title'
post.title_original #=> 'Fraking title'
post.body #=> 'What a bunch of @#$%'
post.body_original #=> 'What a bunch of frak'
By default the filter will replace common curses with the standard curse notation of ’@#$%’. Fu-fu is also has the ability to do dictionary replacements:
class Post < ActiveRecord::Base
profanity_filter :title, :body, :method => 'dictionary'
end
post = Post.create(:title => 'Fraking title', :body => 'What a bunch of frak')
post.title #=> 'fr*k*ng title'
post.body #=> 'What a bunch of fr*k'
Fu-fu comes with a default dictionary file that replaces all vowels with asterisks (*).
You can also add an exclamation point to the end of the filter call (profanity_filter!) and have the method save the filtered text to the database (although this is not recommended for most applications).
You can also call Fu-fu directly:
ProfanityFilter::Base.clean('frak') #=> '@#$%'
ProfanityFilter::Base.clean('frak', 'dictionary') #=> 'fr*k
Todos and Fixes
But alas, there is still danger in Caerbannog. As with all things, there is room for improvement.
* better filter regex, doesn't currently catch things like 'f-r-a-k'
* needs support for multiple dictionaries and configuration
* needs support for different levels of filtering (prude, normal, weak, etc)
Installation
To install the Fu-fu: The Profanity Filter on Edge Rails or Rails 2.1 and greater:
script/plugin install git://github.com/adambair/fu-fu.git
On earlier versions of Rails:
git clone git://github.com/adambair/fu-fu.git vendor/plugins/fu-fu
Resources
Bug tracking is available through the Fu-fu Lighthouse project. Also, feel free to contribute. I’ll be happy to accept patches and push requests for reasonable fixes and additions as long as they come with test coverage.
The source code is available on GitHub.
For general discussion about the plugin, please use the forums and wall of Fu-Fu’s Acts As Community Profile
Thanks to the Intridea team for their time, contributions, and suggestions. I’ve had a great time building Fu-fu and I hope someone may find it useful.
7 Responses to “Announcing Fu-fu: The Profanity Filter for Rails”
rafi - After I saw your comment I went poking around and found that I was doing word lookups against an Array instead of a Hash (which was a mistake on my part). Hash lookups are waaay faster.
I've provided some crude benchmarks for Fu-fu of which the results can be found in the Fu-fu github repo.
I did benchmarks of different sized strings (100, 1000, 5000, 10000 words) and dictionaries (100, 1000, 5000, 25000, 50000, 100000 words) and found that the dictionary size didn't make that much of a different.
10,000 word string 100 word dictionary:
( 0.059946) - single run
10,000 word string 100,000 word dictionary:
( 0.055301) - single run
I would think that most people would be using Fu-fu to filter out shorter strings like comments on a blog or in a forum with a basic dictionary. I could be wrong, but I think this is quite fast enough for that; besides, how many curse words can there be? :)
(Disclaimer: I'm not an expert in benchmarking so please take my numbers with a grain of salt.)
@James -- The service isn't a bad idea, it just depends on your application's specific needs.
@Cheri -- You can certainly add your own set of banned words. The dictionary/substitutions can be found in the config/dictionary.yml. I've been meaning to add the ability for users to be able to specify their own dictionaries without having to deal with the one provided by default. I've created a ticket for this because of your suggestion:
http://adambair.lighthouseapp.com/projects/12000-profanity-filter/tickets/10-allow-configurable-dictionary-files
@Cheri -- You can also change the "@#$%" to a space although it require minor hacking right now. You can find this substitution on line #45 of lib/profanity_filter.rb. This should really be user configurable, just like the dictionary above. I've created a ticket for this as well:
http://adambair.lighthouseapp.com/projects/12000-profanity-filter/tickets/11-allow-users-to-use-their-own-simple-substitution
Thanks for the suggestions!
Sorry, comments are closed for this article.