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.

I’m used to a web dev language Lasso where there is a true persisent
in-memory environment surrounding all requests. Using globals (with some
read/write thread locking) is a great way to create an in-memory cache
for many-reads/occasional-writes.

I can’t seem to recreate this in Rails. I attempted to use global var
like I would in Lasso, but so far that hasn’t proven effective. The var
appears to get recreated (some confusion about the meaning of “global”
there, but that may be another topic).

I have caught wind of memcached, but that sounds like overkill for my
needs (this Rails app will only ever need to run on a single machine).
Actually, I’ll have several machines, but each needs it’s own cache for
this data–unique per machine which again is why the global thing was
perfect in Lasso.

Then there’s the issue of making this data available to multiple
instances of mogrel/Rails. Lasso is multi-threaded, so there was no need
to deal with starting an arbitrary number of handlers like is needed
with Rails.

Anyway, is there a way to create such a critter in Rails, or is
memcached the only option?

– 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.

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.

Philip H. wrote:

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.

If I’m reading that correctly, it can’t be a constant, and can’t be
frozen. The cache builds up over time via lazy loads (the “occassional
write” part).

I tried using a global there, and had other complaints from Rails. I’ll
fiddle some more there then if that’s supposed to be the place to add it
(figured it was, but didn’t work first time, might have been a separate
bug).

– gw

Anyway, is there a way to create such a critter in Rails, or is
memcached the only option?

– gw

Creating a Singleton object won’t get what you need? I’ve used them in
the
past with Java for this sort of requirement.


Andrew S.

On Oct 25, 2007, at 2:31 PM, Philip H. wrote:

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…

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

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.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.

On 10/25/07, Greg W. [email protected] wrote:

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.

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


Greg D.
http://destiney.com/

On Oct 25, 2007, at 2:36 PM, Greg D. wrote:

On 10/25/07, Greg W. [email protected] wrote:

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.

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 10/25/07, Greg W. [email protected] wrote:

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.

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.


Greg D.
http://destiney.com/

On Oct 25, 2007, at 3:04 PM, Greg D. wrote:

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.

On Oct 25, 2007, at 1:12 PM, s.ross wrote:

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

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

On Oct 25, 2007, at 2:31 PM, Philip H. wrote:

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.

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

[email protected] wrote:

You could use the built-in Ruby SDBM persistent hashing solution.
It’s extremely fast and will run under Rails or any Ruby application
on any web server. The best part is it’s included in Ruby - no
plugins or gems!

I covered it on one of my earlier Rubyology screencasts (http://
rubyology.com/mp3s/rubyology25.mov).

OK, cool. Thx.

<% plug(:shameless => true) %>

Have a look at http://www.screencastapp.com/ for your screencasting. (My
son wrote it, and just released it. A lot of satisfied people so far :slight_smile:

<% end %>

– gw

You could use the built-in Ruby SDBM persistent hashing solution.
It’s extremely fast and will run under Rails or any Ruby application
on any web server. The best part is it’s included in Ruby - no
plugins or gems!

I covered it on one of my earlier Rubyology screencasts (http://
rubyology.com/mp3s/rubyology25.mov).

Cheers,
Chris Matthieu
http://www.rubyology.com