Sunday February 15, 2009 21:58 |
0 Comments
It’s been a long time since I posted something in this series, almost 3 years to be exact, and it’s about due.
One of the things that developers do when they are new to the MVC paradigm/Rails is to litter their controllers with all sorts of business rules code. This isn’t a fault really. For beginners it’s a way to get your app and running quickly.
As a developer matures with the MVC paradigm, they begin to see that there is a better way to do things (think Fat Model/Skinny Controller). That certainly was the case with me.
For instance, the create action of my blog’s comment controller (the heaviest action by far) weighed in at a hefty 61 lines of code. After doing a bit of refactoring, my controller has dropped to 25 lines of code. Still not perfect, but all of the comment processing code has been moved into the model.
Let’s take a look at how and why I made the changes.
First thing is first. Since I’m using the Akismet web service to check for comment spam, I need to track the referrer, the IP address of the client, and the User Agent.
I used to have a line of code in the create action that got this information by calling a method in the Application Controller.
options = get_browser_info
That method was defined as:
def get_browser_info
options = { :ip_address => request.env["REMOTE_ADDR"],
:user_agent => request.env["HTTP_USER_AGENT"], :referer => request.env["HTTP_REFERER"] }
end
This worked, but it lacked a little sophistication.
The new method in the Application Controller:
def fetch_browser_info
@browser_info = { :ip_address => request.env["REMOTE_ADDR"],
:user_agent => request.env["HTTP_USER_AGENT"], :referer => request.env["HTTP_REFERER"] }
end
Now in the Comments controller, I can run a before filter on the actions that need this:
before_filter :fetch_browser_info, :only => :create
Unfortunately, the old Akismet plugin that I was using, ror_akismet, enforced the use of extra methods in the controller. I changed this up, by copying the akismet.rb file to my lib directory and removing its dependence on the controller. And yes, I know that ror_akismet is the old library file and rakismet is the replacement. At the time, I didn’t want to install and futz with the new plugin.
That allowed me to pull this entire code block:
if is_spam?(:comment_content => @comment.body, :comment_author => @comment.name,
:comment_author_email => @comment.email, :user_ip => @comment.ip_address,
:referrer => @comment.referer, :user_agent => @comment.user_agent)
That now goes into the model. With a code block that looks like this:
if is_spam?( { :comment_content => self.body, :comment_author => self.name, :comment_author_email => self.email, :user_ip => self.ip_address, :referrer => self.referer, :user_agent => self.user_agent }.merge(self.akismet_attributes))
That’s it for this edition of Buildin’ the Blog, but I’m not done rebuilding my Comments create action. In the next part of the series, I’ll cover how to access variables that aren’t part of your Model’s attributes (table columns) and a quick note about security.