I have a file in my Rails 3.2.11 project called app/queries/visible_discussions.rb which looks like the following:
class VisibleDiscussions
...
end
I'd like to namespace the query so that I can call it using something like Queries::VisibleDiscussions so I tried to do the following:
module Queries
class VisibleDiscussions
...
end
end
However, I'm getting a uninitialized constant Queries (NameError) when I try to call Queries::VisibleDiscussions from the rails console.
Any ideas?
if you add lib to your autoload_paths then it will respect the namespacing under lib - lib/query/visible_discussions.rb
or create a new dir under app - say src and then nest your code there - app/src/query/visible_discussions.rb
i would use the 3rd style in your post for either of these, i.e.
module Query
class VisibleDiscussions
...
end
end
both of these solutions are annoying to me, there might be a way to tell rails to namespace directories under app, but i have no clue how it would be done
Rails needs to know what directories to load (a part from the defaults). Try:
#config.application.rb
config.autoload_paths += %W(#{config.root}/queries)
Related
I have question about naming conventions and autoloading.
I want to have a presenter ItemPresenter in app/presenters/items/item_presenter.rb
My understanding was that I can just create that file like this:
module Items
class ItemPresenter
end
end
But when I do this and try to call the presenter as Items::ItemPresenter I get uninitialized constant error:
uninitialized constant Items::ItemPresenter
def show
#presenter = Items::ItemPresenter.new # this is the highlighted line of my Controller
EDIT: Rails, Custom Folders and Namespaces is not duplicate because it's about different dir structure jobs/smth.rb while I am trying to implement presenters/items/item_presenter.rb (1 more level)
EDIT2: neither it works from rails console: NameError: uninitialized constant Items::ItemPresenter
EDIT2: I tried doing this as suggested:
module Presenters
module Items
class ItemPresenter
def test
"hello"
end
end
end
end
And #presenter = Presenters::Items::ItemPresenter.new in my controller:
uninitialized constant TrialsController::Presenters
It seems like Rails do not see that directory at all.
EDIT3: Created a sample app https://github.com/dontlookforme/test_app
EDIT4: Figured it out. I screwed up the file name (see the answer I've posted)
I found the answer but it's necessary to see #user1556912's sample app (link in the original question) to see what happened.
The problem is that the filename is items_presenter.rb (plural) but the class name is ItemPresenter (singular).
As I pointed out in a comment on #Anthony E's answer, Rails will autoload everything in the /app dir, so it's not necessary explicitly to tell Rails about these files. However, along with namespaces matching dir hierarchies, the names of the classes must also match the names of the files exactly. In this case, I was able to get the class to load in the rails console by renaming items_presenter.rb to item_presenter.rb.
Going back to #Anthony E's answer, though, I do agree that the Items:: namespace seems superfluous here. I would just do app/presenters/item_presenter.rb.
app/presenters/ is the conventional path to store presenters. In fact, you can probably go without folder nesting for items:
app/presenters/item_presenter.rb
You'll need to update the module path accordingly:
module Presenters
class ItemPresenter
def test
"hello"
end
end
end
Then, you can tell Rails to automatically load this file in your application.rb:
config.autoload_paths << '#{config.root}/app/presenters'
Ugh. The thing I was doing wrong is the file name.
I named the preseter file items_presenter.rb but the class had singular Item in the name ItemPresenter.
Fixed that and everything started working.
Thanks for the help guys!
I'm trying to add a method to the DateTime class like so:
class DateTime
def ymd(sep = "/")
strftime("%Y#{sep}%m#{sep}%d")
end
end
I put this in #{config.root}/lib/datetime.rb and updated the autoload_path to include #{config.root}/lib (since that seems to go in and out of the conventional autoload path). That didn't work, so I also tried putting it in a random directory (#{config.root}/blah and added that path to the autoload_paths line in the config).
In all of the above cases, I'm only able to use the new method in the rails console if I require 'datetime' first, and I'm not able to use it in controllers or view templates no matter what I do.
So,
Should the file be called datetime.rb or date_time.rb? (I've tried both so far and neither are currently working)
Where should I be putting this file so I can use the new method in models, controllers and views?
Any idea why I can require it in the console, but it doesn't autoload there?
The app is currently running rails 3.2.21, but I'll switch to rails 4 at some point so answers for either version are appreciated.
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.
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 have a tirable orgnizing my Models in a Sinatra project.
Let's say I have 2 models: Post and Comment, nn Post model, I have to call Comment model. And now I have <class:Post>': uninitialized constant Comment (NameError).
I know its an issue in ordering the requiring for the models, but what about if I have lots of models? What's the Rails way in requiring models, etc.?
UPDATE
I use this code to auto_load my models in Sinatra/Rack/Grape applications. This code should be at the top of your code ie in the boot file.
models = File.join(File.dirname(__FILE__), 'app', 'models') # path to your models
$LOAD_PATH << File.expand_path(models)
# Constent Missing for requiring models files
def Object.const_missing(const)
require const.to_s.underscore
klass = const_get(const)
return klass if klass
end
You should put all of your models in a folder, such as lib in your application, then you can add this to the top of your Sinatra app file:
$: << File.dirname(__FILE__) + "/lib" # Assuming app.rb is at the same level as lib
require 'post'
require 'comment'
You should organise your code so that you do not call other models until all model declarations are loaded.
The Rails way is based on a very nice Ruby feature: const_missing. You could write your const_missing method or looking around the web for a solution with const_missing and sinatra.
no prob when I tried this
a Comment if it is in a method of Post shouldn't be actually evaluated
there must be some circumstance triggering the NameError
don't call Post in the body of the class declaration
load all the model files per the first commenter's suggestion
shouldnt be having the same reference troubles as Java per se
in a dynamic lang like Ruby