2

次のようなものが必要ですが、異なるクラスで再利用できるようにしたいと考えています。

このコードをリファクタリングして、最小限の労力でクラスに含めることができ、そのクラスは new が呼び出されるたびに自動的にインスタンスを収集するようにするにはどうすればよいですか?

new や initialize をオーバーライドするなど、あらゆる種類のことを試しましたが、魔法を起こすことはできません。

   class Person      
      @@people_instances = []

      def initialize
         @@people_instances << self
      end

      def self.instances
         @@people_instances
      end

   end


People.new
People.new
Poople.instances

 => [#<Person:0x000001071a7e28>, #<Person:0x000001071a3828>] 

以下のいくつかのフィードバックの後、答えはインスタンスをクラス変数に入れることではないと思います。インスタンスは永久にメモリに残るからです。インスタンスを保持する必要がないため、Rails キャッシュも適切ではありません。

次のコードでは、クラス変数の代わりにクラス インスタンス変数を使用しています。

http://www.dzone.com/snippets/class-variables-vs-class

class Employee
  class << self; attr_accessor :instances; end
  def store
    self.class.instances ||= []
    self.class.instances << self
  end
  def initialize name
    @name = name
  end
end
class Overhead < Employee; end
class Programmer < Employee; end
Overhead.new('Martin').store
Overhead.new('Roy').store
Programmer.new('Erik').store
puts Overhead.instances.size    # => 2
puts Programmer.instances.size  # => 1

これらのインスタンス変数は、すべての Rails リクエストに固有のものですか、それとも存続しますか?

4

2 に答える 2

4

更新された回答

リクエストの間だけ利用できるようにしたい場合は、以前の回答のどれもそれを行うことができません. リクエストとレスポンスのサイクルの間だけ使用できるようにするための解決策は、コントローラ メソッドで割り当てられたスレッド ローカルを使用することです。次に例を示します。

class YourController < ApplicationController

  around_filter :cache_objects

  protected

  def cache_objects
    Thread.current[:my_objects] = ['my-object', 'my-other-object']
    yield
    ensure
      Thread.current[:my_objects]
  end

end

次に、それを必要とするコードで、Thread.current[:my_objects]それらに対してやりたいことを何でも実行します。Web フレームワークまたはサーバー構造がスレッドを再利用しようとする可能性があるため、 around_filterを使用する必要があります。唯一の実際の解決策は、メモリ リークを回避するために要求が完了した後にスレッドをクリーンアップすることです。


古い答え

何をしようとしているのかはわかりませんが、次を使用してクラスのすべてのインスタンスを簡単に選択できますObjectSpace

ObjectSpace.each_object(String) { |s| puts(s) }

Railsキャッシュを使用するだけのデータベースキャッシュとして必要な場合は、これらのオブジェクトを一度ロードしてからキャッシュに保持します。Rails キャッシュを使用する場合は、オブジェクトをキャッシュに送信するだけです。

Rails.cache.write( "my_cached_objects", [ 'first-object', 'second-object' ] )

そして、それらを別の場所に取得します。

Rails.cache.fetch("my_cached_objects") do 
  # generate your objects here if there was a cache miss
  [ 'first-object', 'second-object' ]
end

ご覧のとおり、 を呼び出す必要さえありません。cache.writefetch を使用するだけで、キャッシュ ミスが発生するたびに、指定されたブロックが呼び出され、オブジェクトが作成されます。

Rails キャッシングの詳細については、こちらを参照してください。ActiveSupport::Cache::Store でサポートされているすべてのメソッドは、こちらで確認できます。

を使用せずに別の方法を使用しObjectSpaceますが、まだ醜い解決策があり、現在は次を使用していalias_methodます:

module Counter

  def self.included( base )
    base.extend(ClassMethods)
    base.class_eval do
      alias_method :initialize_without_counter, :initialize
      alias_method :initialize, :initialize_with_counter
    end
  end

  def count_class_variable_name
    :"@@#{self.class.name.downcase}_instances"
  end

  def initialize_with_counter( *args )
    unless self.class.class_variable_defined?(count_class_variable_name)
      self.class.class_variable_set(count_class_variable_name, [])
    end

    self.class.class_variable_get(count_class_variable_name) << self
    initialize_without_counter(*args)
  end

  module ClassMethods

    def all_instances
      class_variable_get(:"@@#{name.downcase}_instances")
    end

  end

end


class Person

  def initialize
    puts 'new person'
  end

  include Counter

end

p1 = Person.new
p2 = Person.new
p3 = Person.new

puts Person.all_instances.size
于 2012-06-18T03:02:07.760 に答える
2

lib/keeper.rb

def initialize
  instance_eval "@@#{self.class.to_s.downcase}_instances ||= []"
  instance_eval "@@#{self.class.to_s.downcase}_instances << self"
end

def self.instances
  return class_eval "@@#{self.to_s.downcase}_instances"
end

person.rb

class Person
  eval File.open('./lib/keeper.rb','rb').read
end

次に、これは機能します:

Person.new
Person.new
Person.instances
于 2012-06-18T02:59:01.453 に答える