# With\_options Confusion

**URL:** <https://www.ruby-forum.com/t/with-options-confusion/87432>\
**Category:** Rails\
**Created:** [March 2, 2007, 4:27pm UTC](https://www.ruby-forum.com/t/with-options-confusion/87432 "2007-03-02T16:27:35Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![nielsene](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/bc79bd/32.png) [@nielsene](https://www.ruby-forum.com/u/nielsene)\
**Post date:** [March 2, 2007, 4:27pm UTC](https://www.ruby-forum.com/t/with-options-confusion/87432/1 "2007-03-02T16:27:35Z")

</div>

I was looking through the code of attachment\_fu and came across the  
following block pulled from attachment\_fu:60

with\_options :foreign\_key =\> ‘parent\_id’ do |m|  
m.has\_many :thumbnails, :dependent =\> :destroy, :class\_name =\>  
options[:thumbnail\_class].to\_s  
m.belongs\_to :parent, :class\_name =\> base\_class.to\_s  
end

I’ve never seen with\_options called without being tied to a map, e.g.  
map.with\_options, so I opened up the with\_options code to see what was  
going on and with my newbie Ruby knowledge can’t seem to figure this  
one out.

Here’s the object extension in ActiveSupport that gets called

def with\_options(options)  
yield ActiveSupport::OptionMerger.new(self, options)  
end

That seems straight forward but the OptionMerger boggles me. Here’s  
the full module

module ActiveSupport  
class OptionMerger #:nodoc:  
instance\_methods.each do |method|  
undef\_method(method) if method !~ /^(\_\_|instance\_eval|class)/  
end

```
def initialize(context, options)
  @context, @options = context, options
end

private
  def method_missing(method, *arguments, &block)
    merge_argument_options! arguments
    @context.send(method, *arguments, &block)
  end

  def merge_argument_options!(arguments)
    arguments << if arguments.last.respond_to? :to_hash
      @options.merge(arguments.pop)
    else
      @options.dup
    end
  end

```

end  
end

I take it that the object is initialized and then the instance methods  
are iterated over undeffing methods that don’t match the give regex.  
Why? I don’t know. The instance\_methods method would also just apply  
to the OptionMerger class methods right? I also don’t see how the  
private methods are called. Any help to further expand my ruby/  
ActiveSupport knowledge is much appreciated.

Eric

---

<div class="post-metadata">

**Author:** ![nielsene](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/bc79bd/32.png) [@nielsene](https://www.ruby-forum.com/u/nielsene)\
**Post date:** [March 2, 2007, 5:04pm UTC](https://www.ruby-forum.com/t/with-options-confusion/87432/2 "2007-03-02T17:04:41Z")

</div>

On Friday 02 March 2007, Eric N. wrote:

> map.with\_options, so I opened up the with\_options code to see what  
> was going on and with my newbie Ruby knowledge can’t seem to figure  
> this one out.

with\_options is general, not tied to map/routes. Think of it as a  
decorator ([http://en.wikipedia.org/wiki/Decorator\_pattern](http://en.wikipedia.org/wiki/Decorator_pattern)) or AOP-style  
before advice. Its sole assumption is that the last argument of any  
method of the decorated object takes an options hash.

When used as map.with\_options { … } it is the map object that is  
decorated. When no receiver is explicitly given, self is decorated in  
the block.

> class OptionMerger #:nodoc:  
> merge\_argument\_options! arguments  
> end  
> end
> 
> I take it that the object is initialized and then the instance  
> methods are iterated over undeffing methods that don’t match the give  
> regex. Why? I don’t know.

Because that ensures that the existing instance methods that plain Ruby  
objects come with don’t get in the way. Therefore, when you call a  
method on an OptionMerger instance, its method\_missing method is  
called, which in turn merges the common options, defined in the  
enclosing with\_options call, into the options of the current call and  
delegates to the real receiver.

> The instance\_methods method would also just  
> apply to the OptionMerger class methods right?

Yes.

> I also don’t see how the private methods are called.

method\_missing is called by the Ruby runtime, not explicitly.

HTH,  
Michael

–  
Michael S.  
[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
[http://www.schuerig.de/michael/](http://www.schuerig.de/michael/)

---

<div class="post-metadata">

**Author:** ![nielsene](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/bc79bd/32.png) [@nielsene](https://www.ruby-forum.com/u/nielsene)\
**Post date:** [March 2, 2007, 5:43pm UTC](https://www.ruby-forum.com/t/with-options-confusion/87432/3 "2007-03-02T17:43:50Z")

</div>

Not exactly intuitive but very cool. I don’t know why I didn’t realize  
the method\_missing method was called due to the missing methods.

Vielen dank,

Eric
