Ruby/Rails class 变量什么时候初始化?
When do Ruby/Rails class variables get initilalized?
我目前面临的问题是,我的所有对象都使用具有 "same" 初始值的实例变量,而我只读了这个。
def initialize
@available_ids = read_only_value
end
但棘手的事情来了:这个 "read_only_value" 是从 API 中检索到的。为了简单起见,我们假设该值是一个整数数组,并且每月更改一次。
但我不想通过在每次创建对象时检索值来拒绝 API。如果我改用 class 变量呢?
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。
使用redis/memcache怎么样?在 redis/memcache 中缓存 api 值并将到期时间设置为一个月或更短。在初始化器中总是从缓存中提取,如果缓存为零,则调用调用真正的方法 api 并再次缓存它。
加载 class 时发生(阅读:在 Rails 启动期间。)
此外,您不需要 class 变量。 Class 实例变量就足够了:
class Foo
@available_ids = read_only_value
def initialize
@available_ids = self.class.instance_variable_get :@available_ids
end
end
对于您的代码,API 将在定义 class 时被访问,这意味着它只会在您启动应用程序时被访问一次。你可以通过这个例子清楚地看到这一点:
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 包装在自己的 class 中。这样做可以让您独立于使用 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
Rails 有一个内置的 cache,所以按照这些思路应该可以工作:(基于文档中的示例)
class Foo
def available_ids
Rails.cache.fetch('available_ids', expires_in: 24.hours) do
API.fetch_ids
end
end
end
我目前面临的问题是,我的所有对象都使用具有 "same" 初始值的实例变量,而我只读了这个。
def initialize
@available_ids = read_only_value
end
但棘手的事情来了:这个 "read_only_value" 是从 API 中检索到的。为了简单起见,我们假设该值是一个整数数组,并且每月更改一次。
但我不想通过在每次创建对象时检索值来拒绝 API。如果我改用 class 变量呢?
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。
使用redis/memcache怎么样?在 redis/memcache 中缓存 api 值并将到期时间设置为一个月或更短。在初始化器中总是从缓存中提取,如果缓存为零,则调用调用真正的方法 api 并再次缓存它。
加载 class 时发生(阅读:在 Rails 启动期间。)
此外,您不需要 class 变量。 Class 实例变量就足够了:
class Foo
@available_ids = read_only_value
def initialize
@available_ids = self.class.instance_variable_get :@available_ids
end
end
对于您的代码,API 将在定义 class 时被访问,这意味着它只会在您启动应用程序时被访问一次。你可以通过这个例子清楚地看到这一点:
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 包装在自己的 class 中。这样做可以让您独立于使用 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
Rails 有一个内置的 cache,所以按照这些思路应该可以工作:(基于文档中的示例)
class Foo
def available_ids
Rails.cache.fetch('available_ids', expires_in: 24.hours) do
API.fetch_ids
end
end
end