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.
Related
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.
I'm wanting to create a custom directory under app, and have a corresponding namespace, like:
app/my_widgets
and
#app/my_widgets/foo
module MyWidgets
class Foo
#...
end
end
This doesn't work.
LoadError: Unable to autoload constant Foo, expected /project_dir/app/my_widgets/foo.rb to define it.
I am calling:
MyWidgets::Foo.new()
I had guessed this could be because rails autoloads constants from subdirectories of app/... However, adding:
config.autoload_paths += %W{#{config.root}/app"}
Doesn't fix it as I thought it might. Is this a lost cause?
I have tried moving my_widgets/ to something else, eg 'services/' under app, and then everything works as expected.
Is there any way to have a namespace & corresponding directory directly under app/, though?
created a games_account.rb file in the library folder. The following is the structure
module GamesAccounts
class GamesAccountsClient
.
.
.
.
.
end
end
trying to do GamesAccounts::GamesAccountsClient.new in the controller gives me the error
uninitialized constant GamesController::GamesAccounts
I have even added
config.autoload_paths += %W(#{config.root}/lib) in the applications.rb
Am i doing anything wrong here?
I'm not sure about this, but I think you might need to put it in lib/games_accounts/games_accounts_client.rb instead of what you have now, which I presume is lib/games_account.rb. The idea is it should be lib/<module name>/<class name>.rb.
The problem is in your file, name it games_accounts.rb instead of games_account.rb and it should work (because it will match the module name).
If you plan to put many classes within this module, create a directory named games_accounts, and add the class there with the mapping of each file to each class, and put it on your application.rb file, like
config.autoload_paths += %W(#{config.root}/lib/games_accounts)
I have a other thought, If your file is something which is be helping the models than try having it in the form of concerns folder and adding your file there. Since Rails 4 onwards all these support activities will be taken by concerns it's good to adopt right away. Have a read at the blog post by DHH also:
http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns
I have module in /lib/models/scopes.rb
module Models
module Scopes
extend ActiveSupport::Concern
...
end
end
I'm trying to include it from model:
class User < ActiveRecord::Base
include Models::Scopes
end
And getting error:
NameError: uninitialized constant User::Models
How to solve this trouble? Maybe it`s wrong to keep this types of files in /lib?
Environment:
Rails v3.1
Ruby v1.9.3
Rails doesn't require files in the lib directory automatically, but you can add to the autoloaded paths in config/application.rb:
config.autoload_paths += %W(#{config.root}/lib)
Restart the server to pick up the new settings.
This will now load the file automatically when the module name is first used. In development mode, you might want to reload the module after every change in order to see the changes without restarting the server. To do that, add it as an eager load path instead:
config.eager_load_paths += %W(#{config.root}/lib)
The scope shouldn't be a problem as long as you don't have a Models class or module within User or anywhere else.
when you define your class, you're "opening" a new scope. So when you do Models::Scopes, ruby is looking for User::Models::Scopes. You can fix this by using ::Models::Scopes, the :: telling ruby to look in the global scope.
FYI: I'm not sure about the terms I used or even if my train of thought if correct; but the solution should be good anyway. I'd think Ruby would try for ::Models::Scope after failing to find User::Models::Scope, but it doesn't.. Maybe there is a User::Models scope defined somewhere? Anyway, as you can see, I'm not yet familiar with those. You might want to dig on the subject if that interests you
I seem to be having trouble with the naming conventions of the Lib Folder in Rails, and the error messages provided to me do not help. [For example, I have received a message saying that XXX::YYY::TextBox is expected to be defined xxx/yyy/text_box.rb, even though it clearly was defined there.] I think I'm getting the convention wrong.
Let's say I am working on YourModule::MyModule::MyClass. I clearly get that this file should be located in
lib/your_module/my_module/my_class.rb
But what should the actual file here look like? Which one of these (if either) are correct?
#your_module/my_module/my_class.rb
module YourModule
module MyModule
class MyClass
...
end
end
end
Or
#your_module/my_module/my_class.rb
class MyClass
...
end
In other words, do I need to nest the class inside of the module structure or not?
The lib folder has few conventions, as it is not autoloaded. So, how you organize the files is up to you, but you do have to name the classes correctly. Your first example is correct.
To get the files included you need to specify you want them in your application.rb file, see this example: Best way to load module/class from lib folder in Rails 3?
I would recommend making a folder just called lib/modules, since you probably won't have very many. Name the file my_class.rb. Then in application.rb you need:
config.autoload_paths += %W(#{config.root}/lib/modules)
That should take care of your issue.