我有一个包含多个类变量的模块。我正在寻找一个类级别的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调用
答案 0 :(得分:0)
只需使用||=
运算符即可。只有当正确的部分是nil
或false
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