Ruby / Rails类变量什么时候开始初始化?

时间:2017-06-27 14:38:21

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

我目前面临的问题是,我的所有对象都使用了一个带有"相同"的实例变量。初始价值,我只读了这个。

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。

4 个答案:

答案 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