Mixins Don't Replace Inheritance October 4th, 2007
Our application lets you search for businesses based on criteria including name and phone number. Each search could follow a different flow. If a name search returns nothing, check for typos in the name. On a phone search, give up.
This calls for controller inheritance. From a SearchController class, create NameSearchController, PhoneSearchController, etc.
However, Ruby is flexible you can modify an existing class at any point in your application. They can be "reopened." They are prone to abuse.
So instead, we have one giant Search controller. The extracted functionality was moved into modules, which were dynamically added to the main class, or "mixed-in."
Here's a simplified example.
# In name_search.rb
class SearchController < ApplicationController
module NameSearch
module Actions
#name search Specific actions
end
end
end
# In search_controller.rb
require File.dirname(__FILE__) + '/search_controller/name_search'
class SearchController < ApplicationController
include NameSearch::Actions, NameSearch::Reflection
# common search actions
end
What could possibly go wrong?
You live a dangerous life when you're too clever for inheritance. Watch your method names. Every Ruby developer has accidentally defined a method twice, started editing the first definition, and pulled out their hair as their code changes mysteriously have no effect. Imagine the danger splitting things across files.
Now ask: "How do I know what search I'm performing?" After all, in your layout you'll need to know which navigation tab to highlight.
In the mixin setup:
module Reflection
def name_search?
NameSearch::Actions.action_methods.include? params[:action]
end
end
With a subclass:
def name_search?
self.kind_of? NameSearchController
end
helper_method :name_search?
Mixins are perfect for multiple inheritance. You just don't need that here.
The Next Level of Disorganization September 25th, 2007
It's easy to wrong code, but it takes creativity to put the code in the wrong location.
Pop quiz: What goes in a Rails app's tmp/ directory? Let's see:
- sessions files
- pid files
- cache files
- socket files
The pattern is transient files. There are a suite of rake tasks for nuking them. You might as well keep the directory out of subversion.
Today I glance at the commit log, and there are two .rb files. Someone is using tmp as a scratch directory.
So, where should scratch files go? Trick question. Keep it out of subversion.