1

I am currently facing the issue, that all my objects using an instance variable with the "same" inital value and I only read this one.

def initialize
    @available_ids = read_only_value
end

But here comes the tricky thing: This "read_only_value" is retrieved from a API. To make it easy, let's assume the value is an array of ints and gets changed once a month.

But I don't want to DoS the API by retrieving the value every time I create an object. What if I use a class variable instead?

class Foo
   @@available_ids = read_only_value
   def initialize
      @available_ids = @@available_ids //weird but let's go with it
   end
end

I assume this will solve the issue with spamming the API, since it's only execute once the variable gets initialized...

But when does this happen? When I start my Rails application, when I create the first object? Will it ever be updated? Since the value changes once a month how do I get the update?

PS: I guess the best option would be to save the ids in a database and check the ids once in a while or on demand.

4 Answers 4

5

It happens when the class is loaded (read: during Rails startup.)

Also, you don’t need the class variable. Class instance variable is good enough:

class Foo
   @available_ids = read_only_value
   def initialize
      @available_ids = self.class.instance_variable_get :@available_ids
   end
end
Sign up to request clarification or add additional context in comments.

Comments

2

Rails has a built-in cache, so something along these lines should work: (based on the example in the docs)

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

3 Comments

This answer solves my problem, but @mudasobwa was the first to answer my question. I will therefore accept his answer. Thanks anyway!
@0lli.rocks this is not an F1 tournament and race conditions should be avoided. If this answers solves your problem, this answer should be marked as correct. Please do.
@mudasobwa Maybe you misunterstood my comment. My original question was "When are the variables initialized?". This answer by Stefan does not answer this question at all. If I accept this one, someone who finds the question has to scroll to your answer to find the correct answer. Anyway this answer by Stefan solves my problem, not my question.
0

How about using redis/memcache? Cache the api values in redis/memcache and set expiry to one month or little shorter. In the initializer always pull from cache, and if cache is nil, then call the method that calls the real api and again caches it.

Comments

0

In the case of your code, the API would be accessed when the class gets defined, which means it would be accessed only once, when you start your app. You can see this clearly with this example:

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

When trying to manage API access, the best practice is to wrap your API in its own class. Doing so lets you keep track of API calls and cache values independently of the objects using the 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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.