Topic: System Settings

I am trying to determine the best way to set up my app for settings. These are basic parameters that will determine things like

Re: System Settings

One option is to put it directly in the Ruby code. Something that you don't change often like the cookie expiration time should probably go in Ruby. You could set a constant in environment.rb or something.

The other things you may want to change through a web interface so should probably be stored in the database. However, I don't think a generic "settings" table is the way to go. You have to look at each problem individually and probably create a table specific for that problem. For example, sales discounts makes me think it should be a "discounts" table this is related to the "products". Same goes for system wide prices. It really depends on your specific situation.

Railscasts - Free Ruby on Rails Screencasts

Re: System Settings

I thought of doing it that way... in many cases though it will just be a table with one row, which makes me want to rethink my strategy.

Re: System Settings

Another option would be to have a settings table with a "name" column and a "value" column. In the value column you would store a serialized ruby object, so it wouldn't matter if it was a string or an integer or otherwise.

Yet another option, and probably the one I would go with by the sounds of your problem, is to us a file instead of a database table. A YAML file to be exact. Ruby can easily read and write YAML files and serialize complex objects into YAML.

As an example, the ruby hash:

:settings => {:session_timeout => 20, :another_setting => "I like me"}

can be written to and read from the following YAML:

settings:
  session_timeout: 20
  another_setting: "I like me"

I think that's just what the doctor ordered.

Re: System Settings

This sounds awesome!

How do I get Ruby to write YAML to a file?

Re: System Settings

You could use the yaml dump method.

Railscasts - Free Ruby on Rails Screencasts

Re: System Settings

pretty easy, actually:

my_settings = :settings => {:session_timeout => 20, :another_setting => "I like me"}

File.open('path/to/file/settings.yml') do |settings|
  settings << my_settings.to_yaml
end


Stupid simple. And reading YAML is even easier:

my_settings = YAML.load_file('path/to/file/settings.yml')

Nice.

EDIT: Sorry Ryan, didn't see your response. Oh, pimp, I forgot, you might have to require 'YAML', but I think rails does that already. Try without first.

Last edited by fabio (2007-06-28 00:48:44)

Re: System Settings

I guess where I am struggling is in deciding how this fits into the whole MVC picture without a database table. How do I set up my forms and controllers so that the params get sent to YAML?

Re: System Settings

Make a model, but don't inherit from ActiveRecord::Base. It will have to have methods for creating, reading, updating and deleting settings. Here's something to get you started:

class Settings
  SETTINGS_FILE_PATH = 'path/to/settings.yml'

  def self.hash
    @hash ||= YAML.load_file(SETTINGS_FILE_PATH)
  end

  def self.[](sym)
    hash[sym]
  end

  def self.[]=(sym, val)
    hash[sym] = val
  end

  def self.save
    File.open(SETTINGS_FILE_PATH) do |f|
      f << hash.to_yaml
    end
  end

  #other methods
end


This will let you:

Settings[:session_timeout]
#> 1200
Settings[:session_timeout] = 15.minutes
#> 900
Settings.save

This is a naive implementation as you will need to have some error handling, and maybe a method to delete a setting, but it should give you an idea.

Re: System Settings

One more thing: That model might be a good candidate for the singleton pattern, but I honestly don't know enough about it. Ryan, maybe you know more?

Re: System Settings

fabio's suggestion looks good. You may want to expand upon it a little and create accessor (getter and setter) methods for each attribute in the hash. That way it will be easier to use in a form. The singleton pattern will probably work well here.

However, I still question the need for this approach. I know in my experience a few times I thought something like this would be necessary, but I put it off and never ended up needing it. Even if you do need this, I still think there are benefits to keeping it in the database - even if there's only one row. It seems more flexible to me.

Take the classic example of a blog engine. At first you may not want to support multiple blogs, but you need some way to set the name of the blog. IMO it's best to create a Blog model and table with just one row and store the name of the blog in there. Have the Post models belong_to it. Then if you ever do want to support multiple blogs it's easier to add.

Railscasts - Free Ruby on Rails Screencasts

Re: System Settings

I am intrigued by fabio's solution from an intellectual standpoint as I feel it would widen my understanding of Ruby and Rails. But you are probably right Ryan...using the table approach is probably not only easier to implement, but more flexible.

My only apprehension of this appoach is the prospect of having a whole lot of different settings files polluting my MVC directories.. seems like a lot of files being setup just to do a system-wide setting.

I'm gonna do what I should have done to begin with and make a full list of settings that I need for this app, then figure out the best strategy.

In the meantime I will also research singleton methods as I've never used them before. Maybe this could be a future Railscast? wink