Class in Folder autoloading - ruby-on-rails

In one of my controllers I would like to use a Service-Class that I located inside of: services/cars/strategies/unload_car_strategy.rb
Although the unload_car_strategy.rb is located inside the folders, I don't want to use namespacing: The class right now looks like this:
class UnloadCarStrategy
....
end
When I call in my controller UnloadCarStrategy.new I get the error:
NameError: uninitialized constant UnloadCarStrategy
How can I instruct Rails to load this Class?

By default everything under your app/ dir gets auto- and eager- loaded when your application starts. So you got your services dir loaded when the application started.
Even though if you add as many folders and files in those folders you want, Rails will load them for you until you follow the namespacing.
Since you are not using the namespacing the class UnloadCarStrategy doesn't get loaded.
You have to explicitly require it either in the respective controller where it is needed or in the application.rb file.
you either add
require "#{Rails.root}/app/services/cars/strategies/unload_car_strategy" in the controller from where it has to be called
or add the below line to application.rb
config.autoload_paths += %W({config.root}/app/services/cars/strategies/unload_car_strategy.rb)
source : https://gist.github.com/maxim/6503591#if-you-add-a-dir-under-appsomething

Related

Not able to include Module in a Class in Rails Application

I have a class(Server) that include module(ServerConstants)
class Server
include ServerConstants
Both files reside inside lib/server folder
I get an error : Unable to autoload constant Server::ServerConstants
When I use require explicitly it works fine.
I read about Rails Autoloading feature and wonder why it is not picking it up . My application.rb files seems to include autoload paths correctly.
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
What I am missing ?
We are using Rails 4.2.8
Finally I found an answer by Hit and Trial , although I am not sure why it worked.
Instead of defining module like
module ServerConstants
I used
module Server::ServerConstants
and it worked !
Another Finding :
This problem only occurs when you have same name of folder and class including module. In my case server folder contains both Server class and ServerConstants module. When I refactored name of Server to Server_X , the problem faded away.
Include statement directly looks for modules defined without scope or conflicts with names. But when you place it inside lib/server/ directory, it can be access by telling include statement, which directory to look in to find ServerConstants module. That is why if you use include Server::ServerConstants, it works as now you have mentioned which folder to look in and now scope of the module that you want to access is now mentioned.

Way to load folder as module constant in rails app directory

So have a rails 5 project and would like to load a directory like this
/app
/services
/user
foo.rb
as the constant ::Services::User::Foo
Does anyone have experience in getting rails autoload paths to load the constants in this manner?
foo.rb
module Services
module User
class Foo
end
end
end
SOLUTION
Add this to your application.rb file
config.autoload_paths << Rails.root.join('app')
See discussions here on autoloading
https://github.com/rails/rails/issues/14382#issuecomment-37763348
https://github.com/trailblazer/trailblazer/issues/89#issuecomment-149367035
Auto loading
You need to define Services::User::Foo inside app/services/services/user/foo.rb
If you don't want this weird subfolder duplication, you could also move services to app/models/services or lib/services.
You could also leave foo.rb in app/services/user/foo.rb, but it should define User::Foo.
Eager loading
If you don't need any magic with namespaces and class names, it is pretty straightforward :
Dir[Rails.root.join('app/services/**/*.rb')].each{|rb| require rb}
This will eagerly load any Ruby script inside app/services and any subfolder.

Rails Module/Folder Naming Convention

I'm having a problem with a module name and the folder structure.
I have a model defined as
module API
module RESTv2
class User
end
end
end
The folder structure looks like
models/api/restv2/user.rb
When trying to access the class, I get an uninitialized constant error. However, if I change the module name to REST and the folder to /rest, I don't get the error.
I assume the problem has to do with the naming of the folder, and I've tried all different combos of /rest_v_2, /rest_v2, /restv_2, etc.
Any suggestions?
Rails uses the 'underscore' method on a module or class name to try and figure out what file to load when it comes across a constant it doesn't know yet. When you run your module through this method, it doesn't seem to give the most intuitive result:
"RESTv2".underscore
# => "res_tv2"
I'm not sure why underscore makes this choice, but I bet renaming your module dir to the above would fix your issue (though I think I'd prefer just renaming it to "RestV2 or RESTV2 so the directory name is sane).
You'll need to configure Rails to autoload in the subdirectories of the app/model directory. Put this in your config/application.rb:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Then you should be able to autoload those files.
Also, your likely filename will have to be app/model/api/res_tv2/user.rb, as Rails uses String.underscore to determine the filename. I'd just call it API::V2::User to avoid headaches, unless you have more than one type of API.

How to instantiate a class from a different folder structure (Rails)

Using Rails 3.2 and ruby 1.9.3p0
I am trying out the gem delayed_job. I have created a file lib/mailing_job.rb in which I have class MailingJob.
In a controller under app/controllers/requests_controller.rb I am calling
job = MailingJob.new(#request)
but this is returning the error
uninitialized constant RequestsController::MailingJob
I think it is because I need a proper way of referencing a class under a different folder structure.
Any idea how I can isntantiate class MailingJob from a different file (class) in a different folder?
Rails 3 does not include the lib folder within the load path so your application does not know how to find the class.
You can modify config/application.rb and add a line to instruct rails to also look in the lib folder like so
config.autoload_paths += %W(#{config.root}/lib)
In an initializer (e.g. config/initializers/delayed_job.rb), do this (doesnt matter where)
require 'mailing_job'

Subfolders in lib

I have a module called user_searches. It performs some searches that aren't core to the user model, thus, why I'm putting the responsibility somewhere else. I want to organize all my models like this that perform non-core user functions in a lib subfolder called user. Right now to include the module's methods in the User model I have to put...
require 'user/user_searches'
class User < ActiveRecord::Base
include UserSearches
end
...I don't need the require if the file is directly in the lib folder, but do if it's in the subfolder. What do I have to do so I don't need the require?
You could put the necessary require lines into lib/user.rb that way, all requirements are loaded recursively on application launch.
Alternatively, you could put something like this into an initializer:
# put into config/initializers/load_lib.rb
Dir["#{RAILS_ROOT}/lib/**/*.rb"].each { |f| require(f) }
It will require all ruby files in your lib folder. You just have to make sure if this is really what you want :)
This is works that cause
in file rails-2.2.2/lib/initializer.rb in method default_load_paths initialized to load path just the lib folder without subdirectories, to solve this you can edit your project ` environment.rb config file and push into config.load_path array all subdirs.

Resources