【问题标题】:How do I create a singleton global object in rails?如何在 Rails 中创建单例全局对象?
【发布时间】:2012-05-25 23:01:10
【问题描述】:

我有一个对象,我想创建一次并在我的一个模型中访问。我把他放在哪里?恐怕如果我把他放在模型类文件中,每次我创建该模型的新实例时都会创建他。我只希望这个对象在启动时创建一次。这是对象:

require 'pubnub'    
publish_key   = 'fdasfs'
subscribe_key = 'sdfsdsf'
secret_key    = 'fsdfsd'
ssl_on        = false

pubnub_obj = Pubnub.new(publish_key,
                    subscribe_key,
                    secret_key,
                    ssl_on)

我在模型中这样使用他:

class Message < ActiveRecord::Base

  def self.send_new_message_client(message)
    message = { 'some_data' => message }
    info = pubnub_obj.publish({
                            'channel' => 'testing',
                            'message' => message
                          })
    puts(info)
  end

end

【问题讨论】:

标签: ruby-on-rails-3


【解决方案1】:

在 Rails 中,每个请求都会重新创建对象。如果这是某种服务,它应该是请求范围内的单例。

应该使用 ruby​​ 单例 mixin 创建单例对象:

require 'singleton'

class Pubnub
  include Singleton

  def initialize(publish_key, subscribe_key, secret_key, ssl_on)
    # ...
  end

  def publish
    # ...
  end
end

然后你可以用instance方法调用它:

Pubnub.instance.publish

这样你可以确保这个对象实际上是一个单例(只有一个实例存在)。

您可以将它安全地放在models 目录中,尽管我通常更喜欢lib 目录或者可能为服务创建一个新目录。视情况而定。

希望对你有帮助!

【讨论】:

  • 作为记录,只有当 config.cache_classes 设置为 false 时,第一条语句才为 true。默认情况下,在生产中不是这样。我不知道 Singleton mixin 的行为是什么。
  • 在使用像 Phusion Passenger 这样的多进程服务器时,这种方法存在潜在的危险。 PP 为每个请求创建一个线程,此外 - 这些线程可能存在于不同的进程中,因此每个进程都有自己的单例对象,由该进程的多个线程共享。
  • 扩展 Paul 在上面的评论,请注意,如果您不希望共享它还有一个问题,因为希望每个请求都有一个单例。 stackoverflow.com/questions/24927928/…
【解决方案2】:

如果您希望整个应用程序中只有一个实例,请使用单例,否则使用类变量。

要使用单例,请包含 Singleton mixin。

require 'singleton'

class Pubnub
  include Singleton

  attr_writer :publish_key, :subscribe_key, :secret_key, :ssl_on

  def publish
    #...
  end
end

然后像这样使用它:

require 'pubnub'    
class Message < ActiveRecord::Base
  Pubnub.instance.publish_key = 'xyz'
  Pubnub.instance.subscribe_key = 'xyz'
  Pubnub.instance.secret_key = 'xyz'
  Pubnub.instance.ssl_on = 'xyz'

  def self.send_new_message_client(message)
    message = { 'some_data' => message }
    info = Pubnub.instance.publish({
                            'channel' => 'testing',
                            'message' => message
                          })
    puts(info)
  end
end

您还可以将其设为类变量,以将其更紧密地链接到特定模型:

require 'pubnub'    
class Message < ActiveRecord::Base
    @@pubnub_obj = Pubnub.new('xyz', 'xyz', 'xyz', 'xyz')

  def self.send_new_message_client(message)
    message = { 'some_data' => message }
    info = @@pubnub_obj.publish({
                            'channel' => 'testing',
                            'message' => message
                          })
    puts(info)
  end

end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多