I have a module that has multiple class variables. I'm looking for a class level getter implementation that will only instantiate the @@ variable when the class tries to access it like the following
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
I'm looking for this to be transparent so that i don't have to modify the whole module. There are about 10 class level variables with similar functions, all the results of an ActiveRecord .find call
Just use the ||=
operator. It would evaluate the right expression only if the right part is nil
or false
def foo
@@any ||= some_value
end
The first time you call the method it will initialize the variable with the result of some_value
, and following calls will return the @@any
value with no need of recomputing some_value
.
Update
Here it's a little script which shows you how to do that. If you execute that you'll see that the method complex_function
is called once since the two print statements both returns 1. However from your comment I see that your Product
is an active record, so don't use this approach for what your asking for, it will be very inefficient (read the last part of my answer)
#!/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
Update end
However your approach to save Product.all
is pretty inefficient:
Replace your whole method with a Product.find(id)
call.
If your Product
model isn't stored in the db (maybe an ActiveResource) ignore my previous comment.
You could also take a look to mattr_accessor and this SO question Difference between mattr_accessor and cattr_accessor in ActiveSupport?
Finally also take a look to this article which explains the above technique called memoization