微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Rails`NameError:uninitialized constant`仅在生产环境中非控制台-类在/ app子文件夹中-需要添加双冒号`::`

如何解决Rails`NameError:uninitialized constant`仅在生产环境中非控制台-类在/ app子文件夹中-需要添加双冒号`::`

在Rails 5.2应用程序中,我有一个Foos::SomethingSerializer类,存储在app/serializers/foos/something_serializer.rb中。

在开发中,此控制器代码可以正常工作:

# api/v1/foos_controller.rb

  render json: Foos::SomethingSerializer.new(foo).as_json

仅在生产中,此代码引发异常NameError: uninitialized constant Api::V1::Foos::SomethingSerializer

我以前有过这个,所以我刚在它前面添加::,例如:

# api/v1/foos_controller.rb

  render json: ::Foos::SomethingSerializer.new(foo).as_json

我可以称之为一天,但我真的会想了解这一点,因为这些只在生产中受到影响的错误是最糟糕的。

此外,控制台中的Rails.configuration.eager_load_paths显示/app/serializers处于应有的自动加载路径上,因为它是app/的子文件夹。

此外,在生产环境控制台中,我可以毫无例外地键入Foos::SomethingSerializer.new(这样它将找到常量)。

那么为什么(1)在开发中起作用并且(2)在生产中会抛出异常,试图在控制器内部找到该命名空间常量,而在上层Foos命名空间上找不到它?

解决方法

Ruby具有相对恒定的查找。

module A
  class B
    def self.c
      C # note that it's not A::C
    end  
  end  
end  

module A
  class C
  end
end

class C
end

C # C < Object
A::B.c # A::C < Object

如果它可以找到一个相对于您所处位置的常数,则它将返回该常数。如果它无法在当前上下文中找到该常量,它将升至一个级别并在那里寻找它,直到达到根级别为止。如果在根级别上找不到该常量,则会引发错误。

::之前加上常数,指示ruby从根目录开始查找。

在代码中,您同时定义了::FoosApi::V1::Foos。从Foos::SomethingSerializer内部调用Api::V1时,ruby会找到Api::V1::Foos而不是::Foos,但是那里没有SomethingSerializer,因此它将失败。我知道这很不方便,我个人也不喜欢它,但是事实就是这样。如果您知道要从根目录查找某些内容,则始终将::添加为 是安全的。

开发并没有失败,因为您已经自动加载了。当您调用Foos::SomethingSerializer时,尚未加载Api::V1::Foos,并且由于已经加载了::Foos,因此Rails找到了它,并且没有尝试自动加载Api::V1::Foos

我建议您使用eager_load = true运行规范以尝试捕获此类错误,并在根上下文和嵌套上下文中具有相同名称的常量时使用根级查找(::)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。