I'm spending some time reading Rails Antipatterns again. On page 81, there is an example of denormalizing attributes into text fields on a model. I'll simplify the example; please assume state is a column in the article table:
class Article < ActiveRecord::Base
STATES = %w(review published)
validates :state, :inclusion => {:in => STATES}
STATES.each do |state|
define_method "#{state}?" do
self.state == state
end
end
class << self
STATES.each do |state|
define_method "#{state}" do
state
end
end
end
end
What I'm trying to wrap my head around is the methods defined in the class << self block. When you say class << self and define methods within that black, since self is the class Article, I'm defining class methods for Article, right? Article.review, Article.published. I just don't see what the purpose would be. If the purpose is to set some accessors, why wouldn't those be defined in the upper loop where the first "#{state}?" methods are defined.
Is there any way this is a typo? I looked for errata on the book and didn't find anything.
The example in the book is a refactoring from this antipattern:
@article.state = State.find_by_name("published")
to this:
@article.state = State.published
and then to this:
@article.state = Article.published
The last one being implicit and not shown in the book.
As you've noticed, there appears to be little point to making a class method that just returns its own name, so the real point of the example is not that this is the optimal way to do things, but as the book states:
The most important thing is the complexity and code that it not represented here.
i.e. that the dynamically created methods used to be in the State
class and this class was unnecessary and could be removed.
However, there is a further advantage to doing it this way. The purpose of the defined methods is to create a set of constants for the DB column with a standardised interface. Initially, the names of the constants will be the same as the names of the accessor methods, but in future there may be a reason for them to change. In this case, other areas of the program which may be calling these accessor methods can be left as they are.
Contrast this with the alternative of hardcoding the actual string value of the constant all over the place. In that case, knowledge of the database structure of Article
leaks out and creates dependencies, so that changes to the Article
class internals (DB structure) will ripple out to other areas with unpredictable effects. By using messages instead of the actual value of the constant, these dependencies are removed and any refactoring will be trivial if it needs to happen. You can easily redefine any of those dynamic methods to be something more complex without causing anything else outside of Article
to need to change.
In other words: in order to properly encapsulate data, good OO design requires that the knowledge of the names of the database columns should not leave the Article
class. You should always prefer methods over variables in order to make this possible, which is what that block of class methods does.