Ruby on Rails - Global Variable? - ruby-on-rails

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.

Related

Use two neo4j databases in single rails app

I have two neo4j databases running on two different hosts. I connected my rails app to one of them while generating the app. Now I want to use other database as well with the app. How can I configure the app to connect to both the databases?
There’s not currently a good way to configure one Ruby process to use two sessions at the same time. If you are using Rails you can change the server by setting the NEO4J_URL environment variable. Otherwise you’d need to manage the session by setting Neo4j::ActiveBase.current_session or Neo4j::ActiveBase.on_establish_session (which will set the session for each new thread, which may be needed if you are running a multi-threaded process)
See: https://github.com/neo4jrb/neo4j/blob/master/lib/neo4j/active_base.rb
As Brian mentioned currently we cannot configure one Ruby process to use two sessions at the same time. We have to manage the session by setting Neo4j::ActiveBase.current_session (See: https://github.com/neo4jrb/neo4j/blob/master/lib/neo4j/active_base.rb)
The neo4j.yml sets the Neo4j::ActiveBase.current_session for you in the railtie. If you set Neo4j::ActiveBase.current_session after the app has started up it will override what was in the neo4j.yml. The current_session needs to be a Neo4j::Core::CypherSession object from the neo4j-core gem. (See the readme: https://github.com/neo4jrb/neo4j-core)
Also keep in mind, that currently neo4j does not support having different session for each model. So you might experience problem if, setting the session inside model. A better way would be to set session in the normal runtime of the app. You also might want to wrap the Neo4j::Core::CypherSession to get Query Proxy instead of Neo4j::Core objects. To this you have to specify wrap_level: :proc while declaring the adaptor. (Refer: https://github.com/neo4jrb/neo4j/blob/master/lib/neo4j/session_manager.rb#L14)
So in all, here is what you need to do
http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://neo4j:7474',{wrap_level: :proc})
Neo4j::ActiveBase.current_session = Neo4j::Core::CypherSession.new(http_adaptor)
this will establish a wrapped session with the desired database in 'http://neo4j:7474'

Dynamically set a global variable in rails

I was wondering how to initialize and set a global variable in rails. For example if I was building a pizza delivery system and I want the admin to be able to "close" and "open" the place whenever he pleases.
Setting a global variable is simple, just set it $open = false but that won't help you much in a live application because your application will probably be running across multiple processes (each with its own memory, and therefore its own global variables).
The simplest place to start is to just store this state in your database, and check it on each request that comes in where it's relevant.
$pizza_store = :open
That's all. It's global so it doesn't need to be in any sort of namespace, but I would rethink using global variables for any reason.
Start with code school or something similar to learn basic Ruby, then try a more complete tutorial (the Michael Hartl one is good) and learn 'the Rails way' - because if you want to do Rails, you have to do it their way, or you're going to quickly get frustrated.
In addiction to #smathy's answer, if you wanted to avoid using database, simply File.open a index.html in your /public folder, but, of course, you won't be able to use any dynamically generated content on that page.

Keep value in memory across requests and across users in Rails controller? Use class variable?

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?

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.

Ruby on Rails - global variable persistence across requests

In a RoR application, I would like to load a set of key/values from db into a global variable which persists across requests and clear the variable as and when I need. My application runs in a WAS cluster. I tried a few things. 1. Used memcachestore and read/write/clear as needed. 2. Load the key/values in a yaml file and clear it when required. Please let me know if I could do it differently.Thanks.
Don't we have flash and session hashes which can store any object we need?

Resources