Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to store global application settings in a Rails application?

I want to handle two kinds of global configuration settings:

  • Settings which can be altered by the user, like if notification mails for certain events are sent or not.
  • Settings which are tied to a specific product edition, like disabling a feature in a free version, which is only available in the commercial version.

What's the best way to store these settings? Database, configuration file, hardcoded in the source, ...?

like image 921
Daniel Rikowski Avatar asked Oct 11 '09 15:10

Daniel Rikowski


2 Answers

For both cases database. You're going to be using the same structures for multiple people/products so it makes sense. Also it allows you to change things without restarting the server.

I've handled it this way in the past: For settings specific to the user, I've created a UserSettings model/table, that has a one-to-one to relationship with a user. The reasoning for this is that the majority of my operations involving users do no not require these settings to be loaded, so they're only included on user loads from the database when I need them.

When I do this, I'll usually group my column names, so that I can write helpers that dynamically create based on the names. Meaning that I won't have to modify my views to incorporate new settings unless I add one with a different naming scheme.

For the settings specific to a product, well that depends on how you are doing things. And there are a couple of ways to interpret your question.

The way I read it is that you want to decide on a product level. What settings users can overriding or disabling a user's setting. And possibly define some product specific settings.

I would use a one-to-many product to setting relationship. The setting table would be something simplistic (product_id, setting_name, setting_default_value, allow_user_change)

This does a number of things. It lets you have a variable list of settings for different products (Perfect for the case where you're offering many different products instead of varying tiers of access to services). It also lets you define what settings a user can/can't change and give values for that product type. That can be changed from an administrator view without restarting the application. It's also not tied to user settings, to the point where if a user doesn't have a setting listed in the product_settings there will be no problems.

The downside is you will have multiple common settings in this table. I would move settings that every product will have a different value to a field in the product table.

You will also have to write validations to ensure that a user does not change a setting their product says they can't. You will also have to write helper methods to merge settings from the product and user sides.

like image 57
EmFi Avatar answered Sep 27 '22 19:09

EmFi


class Flag < ActiveRecord::Base
  # id, user_id, name, value (serialized probably)

  belongs_to :user

  DEFAULTS = {
    "newsletter" => false
  }

  def self.lookup(user, flag)
    # Please involve memcached here
    case flag
    when "ssl_enabled"
      # Check if user has paid for sufficient access to SSL
      return false
    else
      stored_flag = self.find_by_user_id_and_name(user.id, flag)
      if stored_flag
        return stored_flag.value
      else
        return DEFAULTS[flag]
      end
    end
  end
end

class User < ActiveRecord::Base
  has_many :flags

  def flag(name)
    return Flag.lookup(self, name)
  end
end

For stuff that's product edition based, you probably can't really store things in the database, because the flag is going to be based on some piece of authorization code, rather than static data.

like image 25
Bob Aman Avatar answered Sep 27 '22 17:09

Bob Aman