我目前面临的问题是,我的所有对象都使用了一个带有"相同"的实例变量。初始价值,我只读了这个。
def initialize
@available_ids = read_only_value
end
但是这里有一个棘手的问题:这个" read_only_value"从API检索。为了方便起见,我们假设该值是一个int数组,并且每月更改一次。
但是我不想通过每次创建对象时检索值来执行API。如果我改用类变量怎么办?
class Foo
@@available_ids = read_only_value
def initialize
@available_ids = @@available_ids //weird but let's go with it
end
end
我认为这可以解决垃圾邮件API的问题,因为只有在变量初始化后才执行...
但何时会发生这种情况?当我启动Rails应用程序时,当我创建第一个对象时?它会不会更新?由于价值每月更改一次,我如何获得更新?
PS:我想最好的选择是将ID保存在数据库中并偶尔或按需检查一次ID。
答案 0 :(得分:3)
在加载类时会发生这种情况(读取:在Rails启动期间。)
此外,您不需要类变量。类实例变量足够好了:
class Foo
@available_ids = read_only_value
def initialize
@available_ids = self.class.instance_variable_get :@available_ids
end
end
答案 1 :(得分:2)
Rails有一个内置的cache,所以这些内容应该有效:(基于文档中的示例)
class Foo
def available_ids
Rails.cache.fetch('available_ids', expires_in: 24.hours) do
API.fetch_ids
end
end
end
答案 2 :(得分:0)
使用redis / memcache怎么样?在redis / memcache中缓存api值并将到期时间设置为一个月或更短。在初始化程序中总是从缓存中拉出,如果缓存是nil,则调用调用真实api的方法并再次缓存它。
答案 3 :(得分:0)
对于您的代码,在定义类时将访问API,这意味着当您启动应用程序时,它只会被访问一次。您可以通过此示例清楚地看到这一点:
puts "starting app"
def read_only_value
puts "API accessed!"
"my value"
end
class Foo
@@available_ids = read_only_value
def initialize
@available_ids = @@available_ids
puts "initializing with value: #{@available_ids}"
end
end
puts "initializing two objects: "
Foo.new
Foo.new
#=> starting app
#=> API accessed!
#=> initializing two objects:
#=> initializing with value: my value
#=> initializing with value: my value
尝试管理API访问时,最佳做法是将API包装在自己的类中。这样做可以让您使用API独立于对象跟踪API调用和缓存值:
class API
def self.instance
@@instance ||= API.new
end
def read_only_value
if @read_only_value.nil? || (Time.now - @cached_time) > 86400 # one day, in seconds
puts "accessing api"
@read_only_value = "access api here"
@cached_time = Time.now
end
@read_only_value
end
end
class Foo
def initialize
@available_ids = API.instance.read_only_value
puts "initializing with value: #{@available_ids}"
end
end
puts "initializing two objects: "
Foo.new
Foo.new
#=> initializing two objects:
#=> accessing api
#=> initializing with value: access api here
#=> initializing with value: access api here