問題
Administrate gem
0.16.0
コントローラー
app/controllers/admin/students/users_controller.rb
モデル
app/models/students/user.rb
NameError: uninitialized constant Student::User
File "/app/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.3.3/lib/active_support/inflector/methods.rb", line 284, in const_get
File "/app/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.3.3/lib/active_support/inflector/methods.rb", line 284, in block in constantize
File "/app/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.3.3/lib/active_support/inflector/methods.rb", line 280, in each
File "/app/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.3.3/lib/active_support/inflector/methods.rb", line 280, in inject
File "/app/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.3.3/lib/active_support/inflector/methods.rb", line 280, in constantize
File "/app/vendor/bundle/ruby/2.6.0/gems/administrate-0.16.0/lib/administrate/resource_resolver.rb", line 16, in resource_class
File "/app/vendor/bundle/ruby/2.6.0/gems/administrate-0.16.0/lib/administrate/resource_resolver.rb", line 24, in resource_title
File "/app/vendor/bundle/ruby/2.6.0/gems/administrate-0.16.0/app/controllers/administrate/application_controller.rb", line 186, in translate_with_resource
File "/app/vendor/bundle/ruby/2.6.0/gems/administrate-0.16.0/app/controllers/administrate/application_controller.rb", line 75, in destroy
File "/app/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.3.3/lib/action_controller/metal/basic_implicit_render.rb", line 6, in send_action
backtraceを見ると、Administrate::ResourceResolver#resource_class
あたりで例外が発生しているようだ。
解決策
Administrate::ResourceResolver#controller_path_parts
にモンキーパッチをあてます。
# lib/monkey_patches/administrate.rb
require 'administrate/version'
raise "Consider removing this patch" unless Administrate::VERSION == "0.16.0"
module Administrate
class ResourceResolver
def controller_path_parts
path_parts = controller_path.split("/")[1..-1]
path_parts[-1] = path_parts[-1].singularize
path_parts
end
end
end
モンキーパッチの詳細について
解説
gemのソースコードをみると、Administrate::ResourceResolver
というクラスの機能で、コントローラーのパスから自動でリソースクラス(モデルクラス)を解決しているようです。
例えば、app/controllers/admin/students/users_controller.rb
というコントローラーであれば、自動でStudent::User
というクラスを使用するようになっています。
そう、全て単数形になってしまうんですね。以下の箇所が原因です。
def controller_path_parts
controller_path.split("/")[1..-1].map(&:singularize)
end
もし名前空間が複数形の場合(Students::User
のように)、Student::User
のような名前空間が単数形のクラス名が自動生成されると、名前解決できずNameError uninitialized constant
が発生してしまうんですね。
そういうわけで、コントローラーのパスからモデル名を推測するさいに名前空間を単数形に変換しないようにすれば解決できるというわけです。