Search code examples
ruby-on-railsrubyrails-activerecord

How to check if a Rails model is defined?


I'm using a Ruby on Rails 5.2.8 and Ruby 2.7.8 version and I have found a bug in code. The code should check at runtime if a model is defined. At first I tried to use the defined? method, but because the development environment lazy loads the modules I have encountered unexpected (for me) behaviour:

defined?(ModelToCheck) #=> nil
ModelToCheck
defined?(ModelToCheck) #=> true

so only after using the model it appears to be defined. What is the best way to check if it is defined?

P.S.

the option which configures the lazy loading is:

# config/environments/development.rb
ExampleApp::Application.configure do
  config.eager_load = false

  # rest of the config
  # ...
end

For now I tried to use also Object.const_defined? method, but the same story again.

I have two ideas:

  • don't check at runtime if the model is defined at all
  • use a begin rescue blocks to handle NameError when it is not defined, however it is ugly and I wouldn't like to use it if I could

Solution

  • Since the author of the questions did not want to use #defined? or Object.const_defined? due to autoloading issues, I came up with another solution.

    Yet the best solution would be to fix the autoloading issue, but it's hard to judge that without knowing the internals of the project.


    A way to achieve this is is using #missing_name or #missing_name? and rescuing the thrown NameError:

    begin
      HelloWorld
    rescue NameError => e
      e.missing_name
    end
    # => "HelloWorld"
    

    See the docs for more details.

    Since you find that ugly you can also wrap this into a method something like this:

    def check_defined(constant)
      !!Oject.const_get(constant)
    
    rescue NameError => e
      !e.missing_name?(constant)
    end