在初始化程序中将类实例放入类常量

时间:2017-07-13 07:24:22

标签: ruby-on-rails

在我的一个旧应用程序中,我使用了几个API连接器 - 例如AWS或Mandill。

由于某种原因(可能是我在某个地方看到它,不记得了),我使用类常量来初始化应用程序的初始化阶段。

例如: 的 /initializers/mandrill.rb:

require 'mandrill'
MANDRILL = Mandrill::API.new ENV['MANDRILL_APIKEY']

现在我可以在任何方法中访问我的应用程序的MANDRILL类常量并使用它。 (完整路径MyApplication::Application::MANDRILL,或仅MANDRILL)。一切正常,例如:

def update_mandrill
  result = MANDRILL.inbound.update_route id, pattern, url
end

问题是:使用这样的类常量是一种好习惯吗?或者更好地在使用此实例的每个方法中创建新的类实例,例如:

def update_mandrill
  require 'mandrill'
  mandrill = Mandrill::API.new ENV['MANDRILL_APIKEY']
  result = mandrill.inbound.update_route id, pattern, url
end

2 个答案:

答案 0 :(得分:1)

有趣的问题。

这是非常方便的方法,但在某些情况下它可能有用。

想象一下,您有一个常量要么需要花费大量时间来初始化,要么将大量数据加载到内存中。当它的初始化需要很长时间时,你实际上会降低应用程序启动时间(这可能是也可能不是问题,通常它会在开发中)。 如果它将大量数据加载到内存中,则可能会在运行rake任务时遇到问题,例如加载整个环境。在基本上根本不需要这些数据的用例中,您可能会遇到内存边界。 我知道一个应用程序在启动过程中加载了大量数据 - 而且它是非常刻意完成的。当然,用例有点不常见,但仍然存在。

另一件需要考虑的事情是 - 想象一下,您正试图与Mongo或其他任何东西建立外部服务的连接。如果此服务不可用(会发生什么),您的应用程序将无法启动。也许这项服务对于应用程序的工作至关重要,如果没有它,它将是无用的"无论如何,但你也可以基本上停止一切,因为你保存日志的存储不起作用。

我并不是说你不应该按照你的建议使用它 - 我也是在我的应用程序中使用它,但你应该意识到潜在的缺点。

答案 1 :(得分:1)

是的,预先创建一个伪常量对象(就像那个api客户端)通常是个好主意。然而,大约有一千种方法,并且常数不在我的个人名单之上。

这些天我经常把它设置在env文件中。

# config/environments/production.rb
config.email_client = Mandrill::API.new ENV['MANDRILL_APIKEY'] # the real thing

# config/environments/test.rb
config.email_client = a_null_object # something that conforms to the same api, but does absolutely nothing

# config/environments/development.rb 
config.email_client = a_dev_object # post to local smtp, or something

然后你像这样引用客户端:

Rails.application.configuration.email_client

并且每个环境中都会记录正确的行为。

如果我不需要这种per-env变体,那么我要么使用某种单例对象(EmailClient.get)或初始化器中的全局变量($email_client)。可以认为常量比全局变量更好,从语义上来说,并且当你尝试重新赋值时它会引发警告。但我喜欢这个全局变量更突出。你马上就知道它有些特别。 (然后,它在列表中仅排在第3位,所以我不经常这样做。)。