views:

472

answers:

2

I could use some help on including and extending Ruby modules and classes.

My previous question handled the named routes, but not all of the view/tag helpers due to the default_url_options Hash. The issue here is that ActionController::UrlWriter methods, like url_for, call the class attribute default_url_options. So when including ActionController::UrlWriter it extends the current class singleton but also needs to extend the current class itself. If you look at my code below, MyBigClass should have the default_url_options on it's class, not instance. This works, but I'm not sure if it's correct or will potentially break something.

Here's my current module:

module MessageViewHelper
  module Methods
    def self.included(base)
        base.module_eval do
          include TemplatesHelper
          include LegacyUrlsHelper
          include ActionView::Helpers::TagHelper
          include ActionView::Helpers::AssetTagHelper
          include ActionView::Helpers::UrlHelper
          include ActionController::UrlWriter
        end

        MyBigClass.class_eval do
          cattr_accessor :default_url_options

          def self.default_url_options(options = {})
            options.merge({:host=>'www.myhostname.com'})
          end
        end

      unless ActionController::UrlWriter.method_defined?('old_url_for')
        ActionController::UrlWriter.class_eval do
          alias_method :old_url_for, :url_for
          def url_for(options)
            if options.is_a?(String)
              options
            else
              old_url_for(options)
            end
          end
        end
      end # unless method_defined?
    end
  end
end


class MyBigClass < ActiveRecord::Base
  def message(template_name)
    class << self; include MessageViewHelper::Methods; end
    # ... more stuff here
  end
end

I know I'm not entirely clear on ruby class/module design and extensions. Does anyone have any insight on this? Should the changes on MyBigClass be reverted at the end of message?

A: 

Calling include from within a class method or a class_eval block will bring the included module's definitions into the the class itself. I don't completely understand what you're trying to do, but based on your description, I think you're doing it correctly.

Azeem.Butt
A: 
MyBigClass.class_eval do
  cattr_accessor :default_url_options

  def self.default_url_options(options = {})
     options.merge({:host=>'www.myhostname.com'})
   end
 end

Normally, a class_eval defines regular instance methods on the class.

But, in this case inside the class_eval block you are defining the method on self. self inside the block is MyBigClass, so it would actually create a method in MyBigClass's singleton class. Any method in the singleton class is not an instance method.

andHapp