0

I am working on a Ruby on Rails 6 project, and I am trying to use a class instance variable on an ActiveRecord model. Here is a basic example:

class Model << ApplicationRecord
  @var = AnotherClass.new
  
  class << self
    attr_reader :var
  end
  
  # ...
end

I would then like to be able to use Model.var to access Model's instance of AnotherClass. There are multiple such models, each of them referring to a different AnotherClass, with all the AnotherClasses being subclasses of some BaseClass.

However, I am encountering the following error:

uninitialized constant Model::AnotherClass

Because of the class << self, Ruby seems to be looking for a nested class.

Is there a way to access AnotherClass directly, or is there a better way in general to set this up?

Edit: I solved this with a completely different approach, however I'm still interested to see how you would get around this issue.

Jacob Lockard
  • 1,195
  • 9
  • 24
  • The error you encounter is telling you that the constant `AnotherClass` is not found. Are you sure that is is loaded? Where is `AnotherClass` located? Anything in `lib/` is not covered by the autoloader and you will need to `require 'another_class'` first in those scenarios (or add it to the autoload path). – 3limin4t0r Feb 07 '21 at 22:00
  • @3limin4t0r Thanks, I discovered this about ten 10 seconds before you posted the comment. ;) If you post an answer, I will accept it. – Jacob Lockard Feb 07 '21 at 22:02

1 Answers1

2

The error you receive:

uninitialized constant Model::AnotherClass

Tells you that AnotherClass is not initialized (not loaded/found). Let me use the following context as an example:

class Model
  AnotherClass
end

Ruby will start a constant lookup. This will start from the current namespace (Model) and and if nothing is found move up into the namespace tree. In the above example it will first look for Model::AnotherClass if that cannot be found it will look for AnotherClass, if that cannot be found it will throw the exception you receive.

This error simply tells you that AnotherClass is not loaded.

Anything in th app/ directory is loaded by the autoloader of Rails, however if you use the lib/ directory you have to manually require 'another_class' or add the relevant path to the autoload paths.

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
  • This explains a lot. I didn't realize that Ruby will first look for `Model::AnotherClass` *before* `AnotherClass`. I solved this by moving the `lib/` directory to `app/lib/` as suggested [here](https://stackoverflow.com/questions/38198668/rails-5-load-lib-files-in-production). – Jacob Lockard Feb 07 '21 at 22:18
  • 1
    @JacobLockard alternatively, you can precede a constant with `::` to make Ruby look for it at the top-level, i.e. `::AnotherClass` – Stefan Feb 08 '21 at 11:00
  • @Stefan That would normally work, but it didn't in my case because `another_class.rb` was not being loaded by Rails at all. – Jacob Lockard Feb 08 '21 at 13:49