ruby-on-railsrubytrailblazer

Namespaced class references inside other classes generate uninitialized constant errors


in my Rails app I'm making liberal use of class namespacing like so:

class Person
  class PrimaryEmailAddress
    class Update < Trailblazer::Operation

      def persist(options, **)
        Shared::Property::HasOne::Update.(
          {property_class: PrimaryEmailAddress, property_value: @params[:email_address]},
          'current_user' => self['current_user'], parent_node: options[:person])
      end

    end
  end
end

Unfortunately, the ruby interpreter keeps thinking that my namespaced, embedded functions are part of other class' namespace, and it throws uninitialized constant errors. i.e. at runtime I get an error like this

uninitialized constant Person::Shared::Property

Basically, the interpreter is looking at this function Shared::Property::HasOne::Update and treating it like it's in the Person namespace, when it's not, and then throwing an error.

I can get around the problem by explicitely stating that the function is in the Object namespace, like so Object::Shared::Property::HasOne::Update, but adding Object:: all over the place is annoying and ugly. Is there a better solution anyone knows of? Short of rewriting all of my class names / namespacing.

I imagine part of the problem is that Person::Shared is a valid namespace, and so the ruby interpreter starts treating the Shared::Property:: ... reference like I just forgot to add Person to the beginning.

I really appreciate any feedback!!


Solution

  • Found the answer: by adding :: in front of a class reference, I force the ruby interpreter to look at the top level namespace. i.e. instead of Object::Shared::Property::HasOne::Update I can do ::Shared::Property::HasOne::Update, which I find more readable.

    While there are a fair number of questions about uninitialized constant problems, I had trouble finding this answer because all the questions I found were framed in specific cases, rather then being genericized. It seems likely that this is a duplicate question and I just haven't found the other one, but I'm going to post this QA here in case I'm wrong and this helps someone else running into this same problem.

    This question ended up leading me to the correct answer.