Why doesn't Rails autoload classes from app/services?
Asked Answered
M

5

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.

Mcvay answered 30/9, 2015 at 18:37 Comment(1)
Also, maybe this answer might help. https://mcmap.net/q/275919/-rails-error-while-trying-to-load-a-service-in-a-controllerBoyse
S
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.

Stannite answered 29/12, 2016 at 0:5 Comment(3)
Also, naming matters, see this >> #37547941Hickson
I wonder if this spring isssue will ever bite in production. Specially heroku where i don't know if we can restart springNutbrown
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.Winn
O
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.

Outplay answered 12/1, 2017 at 17:20 Comment(0)
M
15

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

Marmoreal answered 9/12, 2016 at 16:31 Comment(0)
H
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.

Harriettharrietta answered 28/6, 2016 at 20:15 Comment(0)
U
-4

You should include it into autoload_paths:

config.autoload_paths += %W(#{Rails.root}/app/services)
Unpaidfor answered 30/9, 2015 at 18:43 Comment(6)
From what I've understood, everything directly under app is automatically loaded: edgeguides.rubyonrails.org/…Mcvay
@AndreiHorak I've also noticed this. Are you using standard Rails (not Rails-api e.g.)?Unpaidfor
@AndreiHorak i am under the impression that you have to restart the server for the new DIR to be added to the load path...Wheeling
@JoelL actually he tried from command line. So it's probably related to spring.Unpaidfor
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.Mcvay
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.Prurigo

© 2022 - 2024 — McMap. All rights reserved.