72

I'm working on a Rails 4.2 app and have just added app/services/fetch_artists.rb to the structure. Inside this file, I have defined a class FetchArtists; end.

When trying to run rails r 'FetchArtists' it gives me a NameError: uninitialized constant FetchArtists.

I've tried looking at ActiveSupport::Dependencies.autoload_paths and indeed, app/services is not there:

/.../app/assets
/.../app/controllers
/.../app/helpers
/.../app/jobs
/.../app/mailers
/.../app/models
/.../app/controllers/concerns
/.../app/models/concerns
/.../spec/mailers/previews

My question is, why isn't this folder automatically loaded, and what should I do for it to be?

EDIT

Very strange, after repeatedly running the above command with rails runner, the new folder appears on the autoload paths. I have no idea why this happened with such a lag.

Someone suggested this may deal with spring. I would like to hear more on this, since it can possibly help many others in this situation too.

linkyndy
  • 17,038
  • 20
  • 114
  • 194

5 Answers5

125

I encountered the same problem and it seems to be a caching issue with Spring, a process which handles preloading your app. It's used for the web server as well as the console and Rake tasks.

Stopping Spring with bin/spring stop will force Spring to load your app fresh. Now running rails console and inspecting ActiveSupport::Dependencies.autoload_paths will successfully show app/services.

maknz
  • 3,746
  • 3
  • 24
  • 21
  • 4
    Also, naming matters, see this >> https://stackoverflow.com/questions/37547441/gettitng-uninitialized-constant-when-tryhing-to-invoke-my-service-in-rails – user3738936 May 21 '18 at 16:46
  • 1
    I wonder if this spring isssue will ever bite in production. Specially heroku where i don't know if we can restart spring – Zia Ul Rehman Mughal Nov 21 '18 at 12:11
  • Likely not as you'll have added, committed and deployed your new files. Spring will not be running on the Heroku instance that is spun up for you latest deploy. – germs12 Oct 21 '21 at 12:42
28

In my case spring was not watching the app/services directory for changes - restarting Spring would load the class but changes to an existing class or new class would require a restart of Spring for them to apply.

To resolve this issue I added it to the list of directories watched by Spring in config/spring.rb:

%w(
  .ruby-version
  .rbenv-vars
  tmp/restart.txt
  tmp/caching-dev.txt
  app/services
).each { |path| Spring.watch(path) }

and restarted Spring one more time.

Brian
  • 281
  • 3
  • 3
14

I came with a similar problem, and took a quick glance at the Spring docs and found this bit about watchers.

I added the following to my application.rb and things fell into place -

Spring.watch "app/services/**"

I'm no expert here, ymmv.

sbauch
  • 810
  • 9
  • 18
14

I was having the same problem, and found no solution. I'm not patient enough to wait for autoload to load it eventually, so my quick solution was to turn eager_load on, and start my server. It will finally load it. I switched it off afterwards and my classes were still loaded.

Just use: config.eager_load = true

in your config/environments/development.rb

-4

You should include it into autoload_paths:

config.autoload_paths += %W(#{Rails.root}/app/services)
dimakura
  • 7,575
  • 17
  • 36
  • 11
    From what I've understood, everything directly under `app` is automatically loaded: http://edgeguides.rubyonrails.org/autoloading_and_reloading_constants.html#autoload-paths – linkyndy Sep 30 '15 at 19:00
  • @AndreiHorak I've also noticed this. Are you using standard Rails (not Rails-api e.g.)? – dimakura Sep 30 '15 at 19:04
  • @AndreiHorak i am under the impression that you have to restart the server for the new DIR to be added to the load path... – Joel Sep 30 '15 at 19:09
  • 4
    @JoelL actually he tried from command line. So it's probably related to spring. – dimakura Sep 30 '15 at 19:12
  • Yes, I was trying both from `rails runner` and `rails console`. So you may be right, it may come from spring. An answer related to this may be useful for others too, so I'm curious what was spring's involvement in this. – linkyndy Sep 30 '15 at 19:15
  • 3
    Stopping Spring with `bin/spring stop` worked for me and allowed the `app/services` directory to be picked up automatically on next app start. You can confirm the autoload paths from the rails console by examining `ActiveSupport::Dependencies.autoload_paths`. – bfalling Aug 03 '16 at 04:00