Why does trying to use Grape with Rails fail with

2019-02-20 01:45发布

问题:

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 for Twitter::API should be app/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.