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.