Rails being ruby’s killer app, I believe it’s vital to illustrate whatever theoretical consideration with real life rails cases (and not just Coffee, spoon_required gibberish)
So take my image bank: class Asset holds the pictures and i gave it a tagging system. I quikly realized i needed to downcase all tags for consistency so I would not end up with both “Winston Churchill” and “winston churchill” as seperate tags.
acts_as_taggable_on, gives you a whole set of methods… some of which are dynamic given its argument (e.g acts_as_taggable_on(:tags, :people) will give you tag_list, and person_list)
Well 2 years ago i would of done something extremely ugly in my controller like:
params[:asset][:tag_list].downcase....
And just the thought of it makes me sick and consider zen boudhism as an alternative to eating cats.
So now that my controllers are all skinny, i was looking at a way to downcase the argument of tag_list=(arg) in my model. Lets make a short story shorter: tag_list= and person_list= being defined dynamically, they’re just stubs for a more general method: set_tag_list_on(context, new_list, tagger=nil).
Below i’ve summed up my 4 or 5 attempts in two:
To tell you the truth my second attempt was actually
module TagHack
def tag_list=(new_tags)
super(new_tags.downcase)
end
end
but that didn’t work because tag_list is actually dynamically defined directly in the body of the Asset class wheras set_tag_list_on lies in ActiveRecord::Acts::TaggableOn::InstanceMethods so it is higher up in the inheritance chain. And that is true for 95% of all instance methods of any active record plugin.
So as you see, nothing is more easy than “enhancing”, “decorating”, “altering”, “bending” any method
- without touching the original code or endangering other classes using it…
- without resolving to black magic…
- and without polluting your code with methods saying without !
The only constraint is that both the original code and your hack must be in modules ‘bracket’. The good news is that a lot of code (like ActiveSupport and so on) is already concieved that way.
Voilà.
(Next I’ll look at some rails internals and a suggested way to dump alias_method_chain)