简体   繁体   中英

Permanent variable in Rails

Lets say that on top of my Rails app there is a bar with piece of text displayed - latest hot deal, scheduled downtime notfication, something like that. It's a single, on of a kind information that needs to be accessed on basically every request, and may be updated from time to time. What is the best way to achieve this?

What I'd like to do is some kind of permanent global variable (accessible from controllers).

  • It will be updated very rarely, so there's no problem if for some time after update there will be an inconsistency between workers.
  • On the other hand, it should be persistent in case of server fault (periodic backup is enough).
  • It will be accessed really often, so it should be as fast as possible - preferably stay in memory.
  • Also, it's only one of a kind, so I'd really prefer not to bloat the app with a dedicated database model.

Something like that is damn easy in Node.js for example, but I couldn't find a single way to achieve this in Rails. What shall I do?

EDIT

Thanks for the answers so far, but while they're inspiring, I think that I should stress out one key functionality that they're all missing. The variable should be editable inside the app and persistent. While it's possible to edit your variables, in case of server restart I'm back to the default - which is bad.

It really depends on what you are looking for. You could do something very simply by putting it in your application_controller.rb

class ApplicationController < ActionController::Base
   def system_message
     "Come buy our amazing .99 iphone chocolate bar apps, with 100% more gamification!"
   end
end

That function (and string) is then accessible from any controller in your application. You could also specify something in the after_initialize block in your application.rb file.

config.after_initialize do
  ::MYTEXT  = "MY SUPER AMAZING TEXT"
end

You could also create your own file under the initializers directory, which is preloaded in rails.

so siteAnnounce.rb

MYANNOUNCEMENT = "NOW LISTEN TO ME!"

You may also want to check out this Railscast video about site wide announcements

I would store it in the database and let caching take care of it.

I feel that global variables are fine, when appropriate, for code that needs to share that common value in many places but that is the code, not the the user view.
This is clearly true in this case as the OP has bolded 'editable by the app'. So I would have a view that lets the users enter it, it gets stored in a db table and then recalled as needed (as cached once used once).

Well I had faced a similar problem. My problem was I needed a global variable in all the levels (MVC). We went to use Memcache to store the variable. May be you can go for a similar solution. And as an added bonus you can change it throughout the program.

You could declare it as a constant in an initializer:

config/initialzers/foo.rb :

 MYVARIABLE = 'some string'

Accessible from anywhere in your application as MYVARIABLE

Ok, so here's what I did. Instead of just putting the value to an initializer, I've made there a simple class that handles it. The variable itself is stored in a predefined file. Besides of reading the file upon the initialization, the class updates file when the value is changed, and also re-read the file periodically to maintain consistency across workers. I've also put there some basic JSON handling and backup functionality to make life easier.

For anyone interested, here's the important code:

class Pomegranate

  def initialize
    @delay = 30.minutes
    @path = "db/pomegranate.json"
    @valid = Time.now - 1
    validate
  end

  def get(*p)
    validate
    p.inject(@data) {|object,key| object[key] if object}
  end

  def set(*p, q, v)
    hash = p.inject(@data) {|object,key| object[key]||={}}
    hash[q] = v
  end

  def save
    @valid = Time.now + @delay
    File.open(@path,"w") {|f| f.write(@data.to_json)}
  end

  private

  def validate
    if @valid < Time.now
      @data = ActiveSupport::JSON.decode(File.read(@path)) rescue {}
      @valid = Time.now + @delay
      @valid = Time.now - 1 if @data.empty?
    end
  end

end

$pom = Pomegranate.new

Source: Where to put Global variables in Rails 3

Try putting it in your applicaton.rb like this:

module MyAppName
  class Application < Rails::Application
    YOUR_GLOBAL_VAR  = "test"
  end
end

Then you can call it with the namespace in your controllers, views or whatever..

MyAppName::Application::YOUR_GLOBAL_VAR

Another alternative would be using something like settingslogic . With settingslogic, you just create a yml config file and a model (Settings.rb) that points to the config file. Then you can access these settings anywhere in your rails app with:

Settings.my_setting

I've started putting constants and variables like this in the configuration object, eg

TestApp::Application.config.foo = 'bar'
TestApp::Application.config.something = { :a => 1, :b => 2 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM