Active Support has a nifty little helper that can cut down on repetition. A lot of things in Rails like validations, associations, named_scopes, routes etc… take a hash of options as their final parameter. There are times where you use many of these with some common options, for example
1 2 3 4 5 |
|
or maybe you have a bunch of associations which all share an association proxy extension module and some settings
1 2 3 4 5 |
|
Enter with_options
!
1 2 3 4 5 6 7 |
|
Any time you’ve got a bunch of method calls taking some common options, with_options
can help.
So how does it work on the inside? All the with_options
method actually does is yield a special object to its block - all the craftiness is in that object. What we want that object to do is forward method calls to the object we’re really interested in (in this case the Customer class) adding the options before it does so.
As with many such proxy objects we undefine just about every method and just implement method_missing
. The implementation of method_missing
inspects the arguments and merges any options present with the common set defined by the call to with_options
(so individual methods can take extra options or override the common ones) before passing them onto the “real” object.
Originally a limitation was that the last argument just had to be a hash, so for example if you had a procedural named_scope
then with_options
couldn’t work. Luckily a recent commit rectifies this: if the thing you’re trying to merge with is a proc, then with_options
will replace it with a new proc that merges the common options with the result of the call to the original proc. If you’re not on edge you’ll have to wait for 2.3 in order to get this.
While both the examples I gave showed using with_options
on what is essentially model class configuration it is by no means limited to that. You could use it for that sort of configuration on your own classes or just inside a regular method - anytime you are making several method calls on the same object with a hash of options at the end.