3

I'm having a class Dog in app/models/dog.rb and another class Services::My::Deeply::Nested::Dog in app/services/my/deeply/nested/dog.rb.

Now in Services::My (app/services/my.rb), I have a reference to one of the following (no need to distinguish, since the behaviour is exaclty the same in all situations):

  • Deeply::Nested::Dog
  • Services::My::Deeply::Nested::Dog
  • ::Services::My::Deeply::Nested::Dog

No matter which of the above I choose, I always get the following error message:

services/my.rb: warning: toplevel constant Dog referenced by Services::My::Deeply::Nested::Dog

Also, my deeply nested Dog never even gets seen by the interpreter (I found out by using puts and syntax errors, nothing happens).

Possible workarounds (which I all don't like) are:

  • Rename one of the Dog classes
  • Run with RAILS_ENV=production in order to disable autoloading and use eager loading instead
  • require_dependency that points to the deeply nested dog

As a computer scientist, I find none of the above workarounds satisfactory. I would like to understand why my deeply nested Dog is not found without workaround and find out what the state-of-the-art Ruby / Rails solution would be for this problem.

Thanks a lot in advance.

Kalsan
  • 822
  • 1
  • 8
  • 19
  • 2
    If you temporarily remove/rename `app/models/dog.rb`, is your `app/services/my/deeply/nested/dog.rb` autoloaded when you invoke `Dog`? – Eric Duminil Dec 02 '16 at 10:26
  • Just curious, where did you get the idea about `app/services`? stackoverflow.com/questions/40921032/way-to-load-folder-as-module-constant-in-rails-app-directory had the same confusion just yesterday. – Eric Duminil Dec 02 '16 at 11:00
  • 1
    Unfortunately I cannot rename or remove ::Dog - hell would break loose since there are thousands of calls to it elsewhere in the code (it's not really named Dog, I simplified and anonymized the code of a large Rails App before posting it here). – Kalsan Dec 02 '16 at 13:17
  • Concerning the app/services, someone I worked for used it as a convention. – Kalsan Dec 02 '16 at 13:17

1 Answers1

1

app/services/my/deeply/nested/dog.rb should define My::Deeply::Nested::Dog and not Services::My::Deeply::Nested::Dog, for the same reason that app/models/dog.rb doesn't define Models::Dog but just Dog.

With :

#app/services/my/deeply/nested/dog.rb                                                       
module My
  module Deeply
    module Nested
      class Dog
        puts "I'm in %s" % __FILE__
        puts Module.nesting.inspect
      end
    end
  end
end

and

# app/models/dog.rb
class Dog
  puts "I'm in %s" % __FILE__
  puts Module.nesting.inspect
end

and

# app/services/my.rb
module My
  puts "I'm in %s" % __FILE__
  puts Module.nesting.inspect
  Dog
  My::Deeply::Nested::Dog
end

You get :

Loading development environment (Rails 5.0.0.1)
2.3.1 :001 > My
I'm in /home/ricou/www/new_rails_5_app/app/services/my.rb
[My]
I'm in /home/ricou/www/new_rails_5_app/app/models/dog.rb
[Dog]
I'm in /home/ricou/www/new_rails_5_app/app/services/my/deeply/nested/dog.rb
[My::Deeply::Nested::Dog, My::Deeply::Nested, My::Deeply, My]
 => My 
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • Thank you for your reply. Unfortunately, it doesn't solve the problem: 1. Doing any changes in the nested dog file has no effect, since the file never gets read. 2. Removing `Services::` from the path to the nested dog in `my.rb` causes a `NameError`. – Kalsan Dec 02 '16 at 13:36
  • Here's a list of what I tried in `my.rb` and what happened: `Deeply::Nested::Dog => warning: toplevel constant Dog referenced by Services::My::Deeply::Nested::Dog`, `My::Deeply::Nested::Dog => NameError: uninitialized constant Services::My::My`, `::My::Deeply::Nested::Dog => NameError: uninitialized constant My`, `::Services::My::Deeply::Nested::Dog => app/services/my.rb: warning: toplevel constant Dog referenced by Services::My::Deeply::Nested::Dog` – Kalsan Dec 02 '16 at 13:39
  • 1
    Either remove the module `Services` in every rb file inside `app/services` or move `app/services` to `app/services/services`. The given my.rb example works with `Deeply::Nested::Dog`, `My::Deeply::Nested::Dog` and `::My::Deeply::Nested::Dog` – Eric Duminil Dec 02 '16 at 13:45
  • 1
    Another possibility : `config.autoload_paths << Rails.root.join('app')` in your `config/application.rb`, and leaving Services as namespace. – Eric Duminil Dec 02 '16 at 14:48
  • 3
    Thanks a lot. I think your reply is correct, but it cannot work in our environment because of our "very special" configuration which we have to stick to for historical reasons (you know the kind of problem I guess ;-) ) So if anyone else comes across this, if there is no more way out, `require_dependency 'path/to/missed/file'` is the easiest workaround. We tried until today and we think we have no other alternative. Thank you for your effort @EricDuminil – Kalsan Dec 05 '16 at 13:23