Ruby类变量和访问分配

时间:2011-09-22 22:28:06

标签: ruby-on-rails ruby class-variables

我有一个包含多个类变量的模块。我正在寻找一个类级别的getter实现,它只会在类尝试访问它时实例化@@变量,如下所示

    module MyProducts
      @@products = nil

      def self.get_product(id)
        # i'm looking for a way that the first call on @@products does a find via AR                 like the following
        # @@products = Product.all
        # this module is in the lib directory of a Rails 2.3.5 app
        @@products.find do |prod|
          prod.id.eql?(id)
        end
      end
    end

我正在寻找透明,这样我就不必修改整个模块了。大约有10个类级别变量具有相似的功能,所有结果都是ActiveRecord .find调用

2 个答案:

答案 0 :(得分:0)

只需使用||=运算符即可。只有当正确的部分是nilfalse

时,它才会评估正确的表达式
def foo
  @@any ||= some_value
end

第一次调用方法时,它会使用some_value的结果初始化变量,以下调用将返回@@any值而无需重新计算some_value

<强>更新

这是一个小脚本,向您展示如何做到这一点。如果执行该操作,您将看到方法complex_function被调用一次,因为两个print语句都返回1.但是从您的注释中我看到您的Product是一个活动记录,所以不要使用这种方法来满足你的要求,这将是非常低效的(阅读我的答案的最后部分)

#!/usr/bin/env ruby

module Foo
  def self.products
    @@products ||=complex_function
  end

  @@a = 0

  def self.complex_function
    @@a += 1
  end
end

p Foo.products
p Foo.products

更新结束

但是,保存Product.all的方法非常低效:

  • 首先,它会在数据库中获取所有产品,当您拥有大量产品时,这会消耗大量内存
  • 当您拥有大量产品时,您的迭代代码将比数据库慢得多

Product.find(id)电话替换整个方法。

如果您的Product模型未存储在数据库中(可能是ActiveResource),请忽略我以前的评论。

您还可以查看mattr_accessor以及此问题Difference between mattr_accessor and cattr_accessor in ActiveSupport?

最后还要看一下this article,它解释了上面称为memoization的技术

答案 1 :(得分:0)

最好不要使用类变量 - 它们有非常奇怪的行为。看到 http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_variab_1.html

在每种情况下,您都可以使用civars(类实例变量):

module MyProducts
  class << self
    @products = nil
  end
end