For a caching mechanism for my Rails app I am setting a class variable in an instance method which is then later accessed in a class method. This works, but I'm a bit paranoid that there could be a memory leak. Therefore does anyone know if Rails ##class variables are cleared between requests? I have tried this out (on my local development environment), but you never know.
They dont get cleared if you have config.cache_classes = true, which is generally the case in production.
Using class variables is not very good idea because you might have more than one concurrent Rails process(and each process will not share class variables with others).
Consider using some built-in mechanism for caching (using memcached or something else).
Related
I'm just wandering when can I safely use Mongoid.override_database.
If I use it inside Sidekiq worker is DB going to be changed only for the worked which has called the override_database method?
How about using it in standard Rails controller? Is there any situation where it shouldn't be used (where it could cause problems)?
At first I've used .with(database: 'xyz') when I needed to change the DB, but then I've found out that it doesn't work on relational fields...
We're on Rails 3.0.6.
We maintain a list of numbers that changes only once a month, but nearly every page request requires access to this list.
We store the list in the database.
Instead of hitting the database on every request and grabbing the list, we would like to grab the data once and stash it in memory for efficient access.
If we store the list in each user session, we still need to hit the database for each session.
Is there a way to only hit the database once and let the values persist in memory across all users and all sessions? We need access to the list from the controller. Should we define a class variable in the controller?
Thanks!
I think Rails.cache is the answer to your problem here. It's a simple interface with multiple backends, the default stores the cache in memory, but if you're already using Memcached, Redis or similar in your app you can plug it into those instead.
Try throwing something similar to this in your ApplicationController
def list_of_numbers
#list_of_numbers ||= Rails.cache.fetch(:list_of_numbers, :expires_in => 24.hours) do
# Read from database
end
end
It will try to read from the cache, but if it doesn't find it, will do the intensive stuff and store it for next time
The pattern you're looking for is known as a singleton which is a simple way to cache stuff that doesn't change over time, for example, you'll often see something like this in application_controller.rb -- your code always calls the method
def current_user(user_id)
#current_user ||= User.find user_id
end
When it does, it checks the instance variable #current_user and returns it if not nil, otherwise it does the database lookup and assigns the result to the instance variable, which it returns.
Your problem is similar, but broader, since it applies to all instances.
One solution is with a class variable, which is documented here http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_classes.html#S3 -- a similar solution to the one above applies here.
This might be a good solution in your case, but has some issues. In specific, (assuming this is a web app) depending on your configuration, you may have multiple instances of Rails loaded in different processes, and class variables only apply to their specific instance. The popular Passenger module (for Apache and Nginx) can be configured to allow class variables to be accessible to all of it's instances ... which works great if you have only one server.
But when you have multiple servers, things get a little tricky. Sure, you could use a class variable and accept that you'll have to make one hit to the database for each server. This works great except for the when that the variable ... varies! You'll need some way of invalidating the variable across all servers. Depending on how critical the it is, this could create various very gnarly and difficult to track down errors (I learned the hard way :-).
Enter memcached. This is a wonderful tool that is a general purpose caching tool. It's very lightweight, and very, very smart. In particular, it can create distributed caches across a cluster of servers -- the value is only ever stored once (thus avoiding the synchronization problem noted above) and each server knows which server to look on to find any given cache key. It even handles when servers go down and all sorts of other unpleasantries.
Setup is remarkably easy, and Rails almost assumes you'll use it for your various caching needs, and the Rails gem just makes it as simple as pie.
On the assumption that there will be other opportunities to cache stuff that might not be as simple as a value you can store in a class variable, that's probably the first place to start.
Why should we avoid using class variables ## in rails? Is there any security loopholes with that. Please answer as I am new with rails. and I am much using instance variable #variable_name . I tried once ##variable_name .
I know only about class variable is, Class variable is sharable between object
But I really would like to know Why should we avoid using class variables ## in rails?
Simply because they are not thread safe. Many rails=capable servers are multi-threaded. That means there may be multiple running instances of your application at any given time and any request by one of your users is going to be arbitrarily assigned to one of them. Class variables are not shared between processes so there is a possibility that your class variable will be different in a subsequent request.
Even if you deliberately manage to run your app in a single threaded server, there is no guarantee that your app won't be restarted between requests, losing your class variable.
If you want functionality similar to what class variables provide, I strongly recommend that you look into key-value stores such as Memcached or Redis.
I have a particular problem I'm trying to solve in a rails 3 app, and the two common solutions that I'm seeing are these:
Thread.current[:something] = value
and
class Foo
cattr_accessor :bar
end
Foo.bar = value
Are these methods of data storage (and the corresponding retrieval) safe across multiple users making a request to my rails app, at the same time?
I'm concerned about Thread.current, because a web server could use a single thread to serve up multiple requests, right? Or is there something in the way rails handles threads to prevent problems when using Thread.current? I see Acts As Current uses Thread.current to store the current user, so that gives me hope... but I want authoritative confirmation.
I'm also concerned about class level attributes in a production environment, because I would expect rails to cache class objects in memory, for performance reasons. Does a class level attribute get re-used across requests? or is it safe due to something that rails does to handle class attributes across requests? again, i would like authoritative confirmation of this.
... this app uses Ruby 1.9.2#p180, with Rails 3.0.9
Safe enough to store the time zone of the current request:
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/time/zones.rb
I am a new Ruby on Rails user and had a question. I have an idea of what I want my Users DB to look like but was wondering whether or not I should add an additional value to it. Basically I need a variable to signal to all users that it is safe to proceed with a certain action. This variable would be persistent across all users and should be visible to all users, but I want the server to be able to change this variable as well. When programming in other languages, I would use a global variables, so I wanted to check if that is also the case here. If so, would this be the best approach for going about it: Site-Wide Global Variables in Ruby on Rails. Also, how would I update the global variables. Thanks for any help!
A global variable doesn't fit your need. It doesn't spread across all the Ruby processes. If your web server spawns 5 ruby processes to handle 5 request at the same time, the variable defined in the first process won't be visible to the others.
There are other solutions available. You can use a database and store the flag/information on the database. Otherwise, you can use a file and store the value in the file.
The best solution would be an in-memory shared data source, such as memcached or Redis.