【问题标题】:When do Ruby/Rails class variables get initilalized?Ruby/Rails 类变量何时初始化?
【发布时间】:2017-11-30 16:12:15
【问题描述】:

我目前面临的问题是,我的所有对象都使用具有“相同”初始值的实例变量,而我只读取了这个。

def initialize
    @available_ids = read_only_value
end

但棘手的事情来了:这个“read_only_value”是从 API 中检索的。为方便起见,我们假设该值是一个整数数组,并且每月更改一次。

但我不想每次创建对象时都通过检索值来拒绝 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。

【问题讨论】:

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


    【解决方案1】:

    Rails 有一个内置的cache,所以这些方面的东西应该可以工作:(基于文档中的示例)

    class Foo
      def available_ids
        Rails.cache.fetch('available_ids', expires_in: 24.hours) do
          API.fetch_ids
        end
      end
    end
    

    【讨论】:

    • 这个答案解决了我的问题,但@mudasobwa 是第一个回答我的问题的人。因此,我会接受他的回答。还是谢谢!
    • @0lli.rocks 这不是 F1 锦标赛,应该避免比赛条件。如果 this 答案解决了您的问题,则应将 this 答案标记为正确。请做。
    • @mudasobwa 也许你误解了我的评论。我最初的问题是“变量什么时候初始化?”。 Stefan 的这个回答根本没有回答这个问题。如果我接受这个,发现问题的人必须滚动到您的答案才能找到正确答案。无论如何,Stefan 的这个回答解决了我的问题,而不是我的问题。
    【解决方案2】:

    对于您的代码,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
    

    【讨论】:

      【解决方案3】:

      在加载类时发生(阅读:在 Rails 启动期间。)

      另外,你不需要类变量。类实例变量就足够了:

      class Foo
         @available_ids = read_only_value
         def initialize
            @available_ids = self.class.instance_variable_get :@available_ids
         end
      end
      

      【讨论】:

        【解决方案4】:

        使用 redis/memcache 怎么样?将 api 值缓存在 redis/memcache 中,并将到期时间设置为一个月或更短。在初始化器中总是从缓存中拉取,如果缓存为nil,则调用调用真正api的方法并再次缓存它。

        【讨论】:

          猜你喜欢
          • 2013-09-21
          • 2012-06-15
          • 2011-06-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-17
          • 2016-11-03
          • 1970-01-01
          相关资源
          最近更新 更多