为什么尝试将 Grape 与 Rails 一起使用会因 "uninitialized constant API" 而失败?

Why does trying to use Grape with Rails fail with "uninitialized constant API"?

我希望有人能解释为什么 Rails (4.1.8) 和 Grape (0.10.1)

会发生这种情况

所以这是我的 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

并在我的 application.rb 中添加:

config.paths.add "app/api", glob: "**/*.rb"
config.autoload_paths += Dir["#{Rails.root}/app/api/*"]

在那种情况下我得到错误:NameError: uninitialized constant API


但如果我的代码如下所示:

app/api/root.rb同上

然后 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

config/application.rb同上

然后一切正常。

我的问题是为什么我不需要在 v1/root.rbv1/users 中指定模块以及为什么我不需要在 [=23] 中使用 API::Root => '/' =]?

这是因为 app/api 是您 API class 的顶级文件夹,而不是 app

来自 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.

因此 API::Root class 的正确位置实际上是 app/api/api/root.rb,而不是 /app/api/root.rb——尽管 class 在顶级命名空间中的正确位置,这就是为什么你给出的第二个例子(classes 从 API 模块中删除)有效。

不过,我建议您将 API class 放在各自的模块中,然后将它们移动到 app/api.

下的匹配子文件夹中

我试图将我的文件放入 app/api/api,但它对我不起作用。

我找到了一个解决方案,只需将 api 文件夹放入 controller 文件夹即可。我不是 100% 确定问题出在哪里,但我的猜测是它与自动加载的路径有关。

来自Grape's documentation

对于大于 6.0.0.beta2 的 Rails 版本,Zeitwerk 自动加载程序是 CRuby 的默认设置。默认情况下 Zeitwerkapi 变形为 Api 而不是 API。为了使我们的示例工作,您需要取消注释 config/initializers/inflections.rb 底部的行,并添加 API 作为首字母缩写词:

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym 'API'
end