GrapeでActiveAdminを使おうとして泥沼にハマった話

# 背景

`grape`と`activeadmin`を使って、APIの管理画面を作りたかった。
両者とも基本に忠実に、ちょっと手を加えた程度の作り込みだったのがずっと以下のエラーが出てしまった。

```
load_missing_constant': Unable to autoload constant Base,
expected /vagrant/app/apis/api/base.rb to define it (LoadError)
```

# 問題

Grapeの記事は色々まとめられていて、
下記のリンクを見れば分かる通り多くの人が`API::Base`という形でnamespaceを確保し、
`base.rb`を`application.rb`のような扱いで利用している。

- [Grape で Web API 開発 - kzy52's blog](http://kzy52.com/entry/2014/11/07/084023)
- [GrapeをつかってAPIを作成する - It's now or never](http://inon29.hateblo.jp/entry/2015/09/07/083654)
- [CODETUNES · Introduction to building APIs with Grape](http://codetunes.com/2014/introduction-to-building-apis-with-grape/)
- [GrapeでAPIを構築時のメモ](http://qiita.com/taizawa/items/a5cce420298e92b046aa)

自分も同じように`API::Base`でmountして、
`base.rb`を`application.rb`としてモリモリ作り込んでいた。

```sh
apis
└── api
    ├── base.rb
    └── v2
        ├── base.rb
        ├── books.rb
        └── users.rb
```

ある程度作った時に、ActiveAdminを入れてみるとエラーが起きた。

```
load_missing_constant': Unable to autoload constant Base,
expected /vagrant/app/apis/api/base.rb to define it (LoadError)
```

その時の設定はこんな感じ

```rb:routes.rb
Rails.application.routes.draw do
  devise_for :admin_users, ActiveAdmin::Devise.config
  ActiveAdmin.routes(self)

  mount API::Base => '/'
end
```

```rb:config/application.rb
module AppName
  class Application < Rails::Application
    config.paths.add File.join('app', 'apis'), glob: File.join('**', '*.rb')
    config.autoload_paths += Dir[Rails.root.join('app', 'apis', '*')]
    config.middleware.use(Rack::Config) do |env|
      env['api.tilt.root'] = Rails.root.join 'app', 'views', 'apis'
    end
  end
end
```

```rb:apis/api/base.rb

module API
  class Base < Grape::API

    mount V2::Base
  end
end
```

エラーメッセージでは```/vagrant/app/apis/api/base.rb```でBaseを定義してよ！と言われているのだが、ちゃんとしている。
どちらももう一方を読み込まなければ動くので、何かの噛み合わせが悪いようだ。


# 原因

``` 
/home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/dependencies.rb:495:in `load_missing_constant': Unable to autoload constant Base, expected /vagrant/app/apis/api/base.rb to define it (LoadError)
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/dependencies.rb:184:in `const_missing'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/dependencies.rb:526:in `load_missing_constant'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/dependencies.rb:184:in `const_missing'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/inflector/methods.rb:263:in `const_get'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/inflector/methods.rb:263:in `block in constantize'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/inflector/methods.rb:259:in `each'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/inflector/methods.rb:259:in `inject'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/inflector/methods.rb:259:in `constantize'
	from /home/vagrant/.gem/ruby/2.2.2/gems/activesupport-4.2.1/lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
	from /home/vagrant/.gem/ruby/2.2.2/gems/inherited_resources-1.6.0/lib/inherited_resources/class_methods.rb:317:in `initialize_resources_class_accessors!'
	from /home/vagrant/.gem/ruby/2.2.2/gems/inherited_resources-1.6.0/lib/inherited_resources/class_methods.rb:394:in `inherited'
	from /home/vagrant/.gem/ruby/2.2.2/bundler/gems/active_admin-28e8a8f36640/lib/active_admin/base_controller/authorization.rb:2:in `<module:ActiveAdmin>'
	from /home/vagrant/.gem/ruby/2.2.2/bundler/gems/active_admin-28e8a8f36640/lib/active_admin/base_controller/authorization.rb:1:in `<top (required)>'
```

エラーlogを見てみると`activeadmin`のauthorize.rbがエラーを出していた。
が、どうやら`activeadmin`がGrapeの`Base`を読みに行ってエラーを吐いているらしい。

# 解決

以下のように`base`というクラス名を変更した。

```
```sh
apis
└── api
    ├── api_base.rb
    └── v2
        ├── v2_base.rb
        ├── books.rb
        └── users.rb
```

```rb:routes.rb
Rails.application.routes.draw do
  devise_for :admin_users, ActiveAdmin::Devise.config
  ActiveAdmin.routes(self)

  mount API::ApiBase => '/'
end
```

```rb:api_base.rb
module API
  class ApiBase < Grape::API

    mount V2::V2Base
  end
end
```

根本的な解決にはなっていないかもしれないけど、とりあえずこれで動いたので一安心。
皆さんもハマらないように気をつけて下さい。