Rails cannot cache precalculated values across browser requests? (such as remembering n factorial results)
For example, the following code:
class FoosController < ApplicationController
def index
if !@foo.nil?
render :locals => {:bar => @foo}
return
else
@foo = rand 10
render :locals => {:bar => @foo}
end
end
end
if I load localhost:3000/foos
multiple times, it will show different values, and it is no surprise if it is development mode, because Rails reload the controller (and model and view) every time a browser request comes in.
But even when in production mode, when everything is loaded and stay there, @foo
's value won't stay across browser requests? Every time reloading the page on the web browser, a different number is shown. So Rails will wipe all values clean each time? Is there a way to cache or "memoize" the results across requests if we don't use a DBMS?
Surprisingly, I just tried using a class variable, and in development mode, it gives a different number each time. In production mode, the number stays the same on F开发者_StackOverflow中文版irefox, and then Chrome will also show that number all the time, until the server is restarted:
class FoosController < ApplicationController
@@foo = nil
def index
if !@@foo.nil?
render :locals => {:bar => @@foo}
return
else
@@foo = rand 10
render :locals => {:bar => @@foo}
end
end
end
Why can a class variable memoize but an instance variable can't? Is using a class variable a reliable way to "remember things" across request reliably in Rails 2.x, 3.x and Ruby 1.8.7 and 1.9.2?
This is a deliberate and desired behavior, every request instantiates a new controller instance, so that a request doesn't have any trouble dealing with leftovers from the previous requests.
You may want to use the session
or the flash
hashes to store @foo
across requests.
class FoosController < ApplicationController
def index
@foo = session[:foo] ||= rand(10)
render :locals => {:bar => @foo}
end
end
session[:foo]
will be persistent all along the way, but you can use flash[:foo]
if you just want to persist it across one request.
@@foo
designates a class variable, @foo
an instance variable. A new instance of a controller is created on every request. And for caching, I really recommend memcache or something similar (due to the forking nature of production rails servers).
Even if you meemoize the way edgerunner suggests, in production you may have multiple mongrel or thin instances running and each of those controllers will have different flash variables and current approach wont work. Go ahead with what Tass says something like memcache or redis to persist such stuff in memory.
精彩评论