使用 const_missing 引用模块外部的 class

Using const_missing to refer to a class external from the module

我有一个具有以下文件夹结构的应用程序:

# /app/controllers/first_controller.
class FirstController
  def method
    'External'
  end
end

# /app/controllers/second_controller.rb
class SecondController
  def method
    'External'
  end
end

# /app/controllers/foo/first_controller.rb
module Foo
  class FirstController < ::FirstController
    def method
      'Internal'
    end
  end
end

我期望的行为是:

Foo::FirstController#method => "Internal"

Foo::SecondController#method => "External"

所以,如果controller没有在模块中定义Foo,应该实例化外部cass

我尝试创建一个文件 foo.rb:

# /app/controllers/foo.rb
module Foo
  def self.const_missing(name)
    "::#{name}".constantize
  end
end

但是使用它会使 rails 忽略 /app/controllers/foo/*.rb 下定义的所有 类(根本不需要它们)。

我怎样才能得到这个?

如果 Foo 命名空间中存在 class,就让 Rails 来完成这项工作。它也使用 const_missing 来解析 class 名称:

module Foo
  def self.const_missing(name)
    if File.exists?("app/controllers/foo/#{name.to_s.underscore}.rb")
      super
    else
      "::#{name}".constantize
    end
  end
end

输出:

Foo::FirstController.new.method
# => "Internal" 
Foo::SecondController.new.method
# => "External"