How make persistent in-memory objects?

I have data that gets loaded from text files, then parsed into specific
data structures. I need this data to be persistent within the Rails
universe available to every request that comes into Rails.

In environment.rb you could do:

MY_SPECIAL_VAR = "foo"
MY_SPECIAL_VAR.freeze

After that you can access MY_SPECIAL_VAR everywhere. And it doesn't need
to be a string. It could be an array, hash, etc...

You can also make it a little nicer (in terms of how you load it) but the
above will work.

I don't know if this is useful to you, but I did this:

# Provide a container for global option storage
# Both getter/setter and [] access methods are
# provided.

class Options
   @@option_hash = {}

   def self.set(option_name, value)
     option_name = option_name.to_s
     @@option_hash[option_name] = value
   end

   def self.get(option_name)
     option_name = option_name.to_s
     @@option_hash[option_name]
   end

   def self.[]=(option_name, value)
     option_name = option_name.to_s
     self.set(option_name, value)
   end

   def self.[](option_name)
     option_name = option_name.to_s
     self.get(option_name)
   end

   def self.has_key?(key)
     key = key.to_s
     @@option_hash.has_key?(key)
   end

   def self.key?(key)
     self.has_key?(key)
   end
end

Stuck it in ./lib/options.rb

Note that this does not scale across Mongrels or *CGI processes.

Just to play around, I added exactly that to environment.rb, and then tried to output it to a template using <%= MY_SPECIAL_VAR %> and I get an unitialize constant error.

Doesn't matter if I add the declarations at the end of the file or inside Rails::Initializer. I've even stopped and restarted Rails uses mongrel_rails stop|start.

Most puzzering :-\

-- gw

Did you restart your server? Changes to environment.rb won't show up otherwise.

I believe I did. That is, I beat out some commands, but whether they worked...

I'm starting using mongrel_rails start -d -p 3001

I'm stopping with mongrel_rails stop -P /path/to/mongrel.log

I get a "terminated" back, then I start again.

-- gw

On a development setup you would usually just run script/server which
will run mongrel for you. Then it's just Ctrl + C, up, and enter to
restart it.

I started with that using Webrick, then added something (I forget already what I did, edited a file?) so that it would use mongrel instead, but that leaves a Terminal window open with all the noise flying by that I'm not interested in yet, so been using the above -d option.

However, just for giggles, I stopped, then fired up with just script/server. Still get complaint of an undefined constant.

Hrmm.

-- gw

I have data that gets loaded from text files, then parsed into
specific data structures. I need this data to be persistent within the Rails
universe available to every request that comes into Rails.

I don't know if this is useful to you, but I did this:

yeah, I may end up with a proper class for the cache, meanwhile my main propblem is getting a variable to survive across multiple Rails page loads.

Here's a stripped down version of what I am doing.

#! /usr/local/bin/ruby

class ConfigData

  if defined? $configCache == nil
    self.resetCache
  end

  def resetCache
    $configCache = Hash.new
  end

  def getData
    if $configData.has_key?('testing')
      puts 'found in cache'
    else
      $configData.store('testing','test data')
      puts 'added to cache'
      p $configData
    end
  end
end

x = ConfigData.new
  
3.times do |i|
  x.getData
end

y = ConfigData.new
  
3.times do |i|
  y.getData
end

This works as expected with all accesses after the first one pulling from the global. Like I say, it's a cheap way to have a cache created on the fly dedicated to the needs of just this class.

If I put this into a rails project as /lib/config_data.rb (separated for ERB template, etc), I also get what I expect on the first pass. First load creates the global and populates the cache. After that the .getData pulls from the global.

The problem I am having is that when I reload the test page, I would expect to see _all_ .getData calls pull from the cache -- meaning the global is stil intact and still has data. Instead I see a repeat of the first pass. The global has to be created and populated, then subsequent .getData calls pull from the global.

This is where I'm puzzled, and where a global is either not a global, or the way Rails runs inside Ruby is working differently than I expected.

If I move the global declaration to environment.rb, I gets complaints from Rails that it was never declared -- so, whatever is going on there I think is the real problem.

Appreciate everyone chipping in so far. Thx.

-- gw

Following up on this one, I'm still having no luck even toying with this.

I've gone so far as to do this:

# Specifies gem version of Rails to use when vendor/rails is not present
RAILS_GEM_VERSION = '1.2.5' unless defined? RAILS_GEM_VERSION

MY_TEST_VAR = "foo"

And in a given template I can output RAILS_GEM_VERSION just fine, but MY_TEST_VAR cause a crash with an undefined contstant error. What is up with that one ??

It doesn't matter what var I declare at any point inside environment.rb or development.rb, every one crashes saying it has not been declared. Freaking me out.

-- gw

Well, after all was said and done I ended up rebooting the whole machine, and that seems to have cured whatever the heck was going wrong. Even stopping and starting the server had no effect. Something was hosed.

My global cache thing works as expected, and that weird inability to add vars to environment.rb is fixed.

Thanks to everyone for your suggestions.

-- gw