Reputation: 8276
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
?
Upvotes: 2
Views: 4548
Reputation: 915
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
Upvotes: 6
Reputation: 1207
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.
Upvotes: 1
Reputation:
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::API
should 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
.
Upvotes: 8