问题
I would like someone to explain why this is happening in Rails (4.1.8) with Grape (0.10.1)
so this is my API:
app/api/root.rb:
module API
class Root < Grape::API
prefix 'api'
mount API::V1::Root
end
end
app/api/v1/root.rb:
module API::V1
class Root < Grape::API
version 'v1'
mount API::V1::Users
end
end
app/api/v1/users.rb:
module API::V1
class Users < Grape::API
format 'json'
resource :users do
desc "Return list of users"
get '/' do
User.all
end
end
end
end
config/routes.rb:
Rails.application.routes.draw do
mount API::Root => '/'
end
and in my application.rb I added:
config.paths.add "app/api", glob: "**/*.rb"
config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
and in that case I get the error: NameError: uninitialized constant API
but if my code looks like:
app/api/root.rb same as above
then app/api/v1/root.rb:
class Root < Grape::API
version 'v1'
mount Users
end
app/api/v1/users.rb:
class Users < Grape::API
format 'json'
resource :users do
desc "Return list of users"
get '/' do
User.all
end
end
end
config/routes.rb:
Rails.application.routes.draw do
mount Root => '/'
end
and config/application.rb same as above
Then everything works fine.
My question is why don't I need to specify modules inside v1/root.rb and also inside v1/users and also why I don't need to use API::Root => '/' in config/routes.rb?
回答1:
It's because app/api is the top-level folder for your API classes, not app.
From Grape's documentation:
Place API files into
app/api. Rails expects a subdirectory that matches the name of the Ruby module and a file name that matches the name of the class. In our example, the file name location and directory forTwitter::APIshould beapp/api/twitter/api.rb.
Therefore the correct location for an API::Root class would actually be app/api/api/root.rb, not /app/api/root.rb—though that is the correct location for a class in the top-level namespace, which is why the second example you give (with classes removed from the API module) works.
I recommend you keep your API classes together in their own module, though, and move them to a matching subfolder beneath app/api.
回答2:
I tried to put my files into app/api/api, but it wasn't working for me.
I found a solution by simply putting the api folder into the controller folder. I'm not 100% sure what the problem was, but my guess is that it has something to do with the auto-loaded paths.
回答3:
From Grape's documentation:
For Rails versions greater than 6.0.0.beta2, Zeitwerk autoloader is the default for CRuby. By default Zeitwerk inflects api as Api instead of API. To make our example work, you need to uncomment the lines at the bottom of config/initializers/inflections.rb, and add API as an acronym:
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'API'
end
来源:https://stackoverflow.com/questions/28109784/why-does-trying-to-use-grape-with-rails-fail-with-uninitialized-constant-api