2012-05-25 3 views
20

J'ai un objet que je veux créer une fois et accessible dans l'un de mes modèles. Où est-ce que je le mets? J'ai peur que si je le mets dans le fichier de classe de modèle, il sera créé chaque fois que je crée une nouvelle instance de ce modèle. Je veux seulement que cet objet soit créé une fois au démarrage. Voici l'objet:comment créer un objet global singleton dans les rails

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) 

Je l'utilise comme celui-ci dans le modèle:

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 
+0

Je pense que vous pouvez utilisez également une variable globale, voir cet exemple ici: https://github.com/pubnub/ruby/blob/master/examples/pubnub_livestream/config/initializers/pubnub.rb –

Répondre

31

Dans Rails, sont recréées objets sur chaque demande. S'il s'agit d'un service, il doit s'agir d'un singleton dans le cadre d'une requête.

objets Singleton devraient être créés avec le singleton rubis mixin:

require 'singleton' 

class Pubnub 
    include Singleton 

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

    def publish 
    # ... 
    end 
end 

Ensuite, vous pouvez appeler la méthode instance:

Pubnub.instance.publish 

De cette façon, vous assurez-vous que cet objet sera effectivement un singleton (une seule instance existera).

Vous pouvez le placer en toute sécurité dans le répertoire models, bien que je préfère souvent le répertoire lib ou peut-être créer un nouveau répertoire pour les services. Ça dépend de la situation.

J'espère que ça aide!

+0

Pour mémoire, la première déclaration n'est vraie que si le config.cache_classes est défini sur false. Ce qui est, par défaut, pas vrai dans la production. Je ne sais pas quel est le comportement avec le mixin Singleton. – Michael

+1

Il existe un danger potentiel dans cette approche lorsque vous utilisez un serveur multiprocessus tel que Phusion Passenger. PP crée un thread par requête et de plus - ces threads vont probablement exister dans des processus séparés, de sorte que chaque processus aura son propre objet singleton partagé par plusieurs threads de ce processus. – Paul

+0

pour étendre le commentaire de Paul ci-dessus, sachez qu'il y a aussi un problème si vous ne voulez pas qu'il soit partagé, en ce sens que le désir est d'avoir un singleton par requête. http://stackoverflow.com/questions/24927928/singleton-in-scope-of-a-request-in-rails – futbolpal

2

Si vous ne voulez qu'une instance dans l'ensemble de votre application, utilisez un singleton, sinon utilisez une variable de classe.

Pour utiliser un singleton, incluez le singleton mixin.

require 'singleton' 

class Pubnub 
    include Singleton 

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

    def publish 
    #... 
    end 
end 

puis l'utiliser comme ceci:

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 

Vous pouvez également faire une variable de classe, de lier plus étroitement à un modèle spécifique:

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