Sometimes you want to modify a model’s behaviour for different environments.
For example, you may have a Comment#is_spam? method which goes off to Akismet and checks whether it’s spam. In development you might want the method to always return true, preventing it from calling Akismet. In other words we want to “mock” the Comment#is_spam? method whilst in development.
The stock-standard Pickaxe way of doing this might be to “reopen” your model class and add the method:
class Comment
def is_spam?(permalink); false end
end
There’s nothing exactly wrong with this method, but you have to remember that Rails lazily loads everything. If you want to alias a method, or do some other manipulation on the class, you can’t because it doesn’t yet exist.
You’ve probably used the above method just fine on one of Ruby’s core classes, such as Time. Ruby has already require’d the Time class before your code executes so you don’t need to worry about whether it exists or not.
One possible fix for the lazy loading is to reference the Comment class before you manipulate it:
Comment # Rails will find and require your model class
class Comment
# Now you can do your mocking
end
A sexier and cleaner way to do this is to use Module#class_eval:
Comment.class_eval do
def is_spam?(permalink); false end
end
In the code above we’re calling a method on the Comment class and, as the Comment constant does not yet exist in Ruby’s ObjectSpace (Ruby throws a NameError), Rails will go and search the load path and require your Comment model for you.
So how to hook this into your config files? Why, config.after_initialize of course!
(if you haven’t heard about after_initialize I highly recommend you read my last article on the Rails initialisation process)
In my case, I just added the following to config/environments/development.rb:
config.after_initialize do
Comment.class_eval do
def is_spam?(permalink); false end
end
end
So there you go: super-simple mocking, using nothing but standard Ruby.
Archived comments
Comments were previously allowed on articles. Though no new comments are being accepted you can see the old comments below.
-
thank you for the simple example