如何防止 Ruby 将 gem 的 class 而不是我的 class 作为目标?
How can I prevent Ruby from targeting a gem's class instead of my class?
我在使用 official SendGrid gem 的 Rails 代码库中遇到问题。同一行为发生了两个不同的实例。
第一个例子
我有一个 Engine
class:
module API
class Engine < ::Rails::Engine
isolate_namespace API
end
...
end
我曾经在我的路线中这样指代那个class:
mount API::Engine, at: :api, as: :api
...但我偶尔会遇到此错误:uninitialized constant SendGrid::API:Engine
。 (我的意思是字面上的“偶尔”;它似乎是在开发过程中随机发生的,刷新会修复它。)因此,我将行更改为:
mount ::API::Engine, at: :api, as: :api
我认为应该明确地针对 my API
而不是 SendGrid 的,但是在开发过程中,当我处理与 SendGrid 相关的代码时,我仍然偶尔会遇到错误.
第二个例子
这个似乎更陌生。这个问题是这周才出现的,让我意识到上面的例子并不是一个孤立的事件。
我有一个 Response
class:
class Survey::Response < Sequel::Model Sequel[:survey][:responses]
...
end
我们的监控刚刚发现了这个错误:
NoMethodError
undefined method `[]' for SendGrid::Response:Class
...这一行:
results = results.pluck(:response_id).uniq.map { |r| Survey::Response[r] }
这个例子似乎更加极端,因为我们明确针对 Survey::Response
而显然不针对 SendGrid::Response
.
问题
我很想知道是什么原因造成的,但主要是我想知道如何阻止它。我怎样才能 100% 确定一行目标是 my class 而不是 sendgrid-ruby
gem 的 class?
我确实找到了 this question,它得出了与我在第一个问题中相同的结论,尽管这个问题的问题已经解决,而我的没有。
我的问题是一个模块被包含在全局命名空间中,因此它的常量污染了整个代码库。
例如:
require 'sendgrid-ruby'
include SendGrid
module MyModule
...
end
以这种方式包含 SendGrid
可能会导致我的问题中描述的问题。以这种方式包含任何 gem 都有可能导致类似的问题。
解决方案是只在必须的地方包含模块,例如:
require 'sendgrid-ruby'
module MyModule
include SendGrid
...
# I can refer to Email here, and it will target SendGrid::Email
...
end
...甚至更好,根本不包含模块,而是明确引用模块的 类:
require 'sendgrid-ruby'
module MyModule
...
# Instead of referring to Email, I must explicitly refer to SendGrid::Email
...
end
帮助我识别了这个问题。但由于在我的搜索中没有出现这个问题,我将把这个问题留在这里,并为未来的旅行者提供答案。
我在使用 official SendGrid gem 的 Rails 代码库中遇到问题。同一行为发生了两个不同的实例。
第一个例子
我有一个 Engine
class:
module API
class Engine < ::Rails::Engine
isolate_namespace API
end
...
end
我曾经在我的路线中这样指代那个class:
mount API::Engine, at: :api, as: :api
...但我偶尔会遇到此错误:uninitialized constant SendGrid::API:Engine
。 (我的意思是字面上的“偶尔”;它似乎是在开发过程中随机发生的,刷新会修复它。)因此,我将行更改为:
mount ::API::Engine, at: :api, as: :api
我认为应该明确地针对 my API
而不是 SendGrid 的,但是在开发过程中,当我处理与 SendGrid 相关的代码时,我仍然偶尔会遇到错误.
第二个例子
这个似乎更陌生。这个问题是这周才出现的,让我意识到上面的例子并不是一个孤立的事件。
我有一个 Response
class:
class Survey::Response < Sequel::Model Sequel[:survey][:responses]
...
end
我们的监控刚刚发现了这个错误:
NoMethodError
undefined method `[]' for SendGrid::Response:Class
...这一行:
results = results.pluck(:response_id).uniq.map { |r| Survey::Response[r] }
这个例子似乎更加极端,因为我们明确针对 Survey::Response
而显然不针对 SendGrid::Response
.
问题
我很想知道是什么原因造成的,但主要是我想知道如何阻止它。我怎样才能 100% 确定一行目标是 my class 而不是 sendgrid-ruby
gem 的 class?
我确实找到了 this question,它得出了与我在第一个问题中相同的结论,尽管这个问题的问题已经解决,而我的没有。
我的问题是一个模块被包含在全局命名空间中,因此它的常量污染了整个代码库。
例如:
require 'sendgrid-ruby'
include SendGrid
module MyModule
...
end
以这种方式包含 SendGrid
可能会导致我的问题中描述的问题。以这种方式包含任何 gem 都有可能导致类似的问题。
解决方案是只在必须的地方包含模块,例如:
require 'sendgrid-ruby'
module MyModule
include SendGrid
...
# I can refer to Email here, and it will target SendGrid::Email
...
end
...甚至更好,根本不包含模块,而是明确引用模块的 类:
require 'sendgrid-ruby'
module MyModule
...
# Instead of referring to Email, I must explicitly refer to SendGrid::Email
...
end