0

Setup:

We got an initializer (in config/initializers) that requires a file where we define our extensions.

This file does something like this:

module UbiquoExtensions
end

:SomeClass.include!(UbiquoExtensions::SomeClass) 

# Classes that overwrite behaviour need to be fully loaded first <- not my comment, it's the original developer's
Rails.application.config.after_initialize do

   AnotherClass.send(:include, UbiquoExtensions::AnotherClass)

end

extension files look like this:

module UbiquoExtensions
  module SomeClass

    def self.included(klass)
      klass.module_eval do

        scope :some_extra_scope, where(something: true)

      end
    end

  end
end

The problem:

I added another extension for a class (Locale). This works fine from most of the code (both original and extended methods work). But it does not work when called from another extension (eg. AnotherClass). When accessing Locale from the extension, it seems it points to the Locale extension:

enter image description here

But both original and extended methods are undefined (undefined method ... for UbiquoExtensions:...).

I have tried putting Locale.send :include, UbiquoExtensions::Locale both inside and outside of Rails.application.config.after_initialize and both before and after the dependant class. I have also checked that when I reach AnotherClass.send(:include, UbiquoExtensions::AnotherClass), while initializing, I have access to all methods just fine.

8
  • Do you understand the difference between modules and classes? This code and question is very confusing as you're declaring modules named SomeClass and AnotherClass. Classes in Ruby are used for vertical inheritance and a class is never used to extend another. Modules are used for horizantal inheritance and can be extended by other modules or included in classes.
    – max
    Commented Jul 10 at 12:59
  • 1
    This code is also doing crazy levels of monkeypatching and metaprogramming in a bad way. scope is just syntactic sugar for declaring class methods and if you want to create a module that provides class methods just declare them as instance methods of the module and use include instead of extend. If you want to declare both class and instance methods use the inner ClassMethods module pattern (or class_methods from ActiveSupport::Concern). stackoverflow.com/questions/33326257/…
    – max
    Commented Jul 10 at 13:03
  • 1
    Can you provide an actual example of what is occurring here? What error are your receiving (with stacktrace)? Where does this error come from? Can you provide a reproducible setup? Commented Jul 10 at 15:43
  • @max AnotherClass is an actual class, UbiquoExtensions::AnotherClass is a module that we use to add methods to said class. We use the same name as the classes for context. Commented Jul 11 at 12:08
  • 1
    This is because the way that module_eval doesn't actually change the module nesting (only the class and module keywords do) so you get wierd and wonky module lookups. That was why I recommended you don't do this and instead declare your monkey patches in a more sane way. justinweiss.com/articles/…
    – max
    Commented Jul 11 at 12:13

1 Answer 1

1

The problem was solved by using::Locale instead of Locale in the UbiquoExtensions::AnotherClass module. This way it references the correct class.

It might have been due to the module being named the same as the class (which we do by convention to keep the context) but I did not try changing the name to prove it.

2
  • When looking for a constant like a class or module, Ruby starts in the current context and moves up if it can't find anything. Meaning that if you're in the context of UbiquoExtensions and you're accessing Locale. Ruby will first try UbiquoExtensions::Locale if that doesn't exist it tries Locale. By prefixing it with :: you're telling Ruby to explicitly use the Locale in the root context.
    – 3limin4t0r
    Commented Jul 11 at 12:27
  • yes, that makes, sense, although the method that was defined in UbiquoExtensions::Locale was not accessible either, that seemed weird, doesn't it? Commented Jul 11 at 12:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.