Search code examples
ruby-on-railsfallbackuser-preferences

(Rails) Managing USER PREFS with a MASTER PREFS fallback...?


I'm looking for a mechanism by which to facilitate user preferences. I also want to have a set of "master" prefs that are used if the currently logged in user doesn't have a specific pref set. I see several questions similar to this, but they seem to get into theory instead of simply proposing a quality solution.

Basically I'm looking for input on management as well as storage -- models, controllers, etc. Initially I was considering simply going with a normalized table of 50+ columns (for performance etc.). However, I plan on adding various, unknown preferences in the future and, performance aside, I could imagine multiple columns getting out of hand. Thoughts?


Solution

  • In my mind, the best way to define and use defaults is to add another row in the user preferences table, and load it as a class variable in your model. Then override the accessors to find the defaults if the preference hasn't been found. Something like this:

    class UserPreference < ActiveRecord::Base
      # load default preferences as a class variable
      @@defaults ||= find(1).attributes
    
      # redefine accessors or each column to load default if nil
      column_names.each do |column|
        method_name = "#{column}_with_default".to_sym
        send :define_method, method_name do 
          value = send("#{column_without_default}") 
          case value
          when nil
            @@defaults[column]
          else 
            value
          end
        end
        alias_method_chain column, :default
      end
      ...
    end
    

    Essentially the default preferences (loaded from row 1) are stored in the Model as a class variable. All the accessors are redefined and made part of an alias method chain so that the default would be returned if the returned value was nil. I wanted to use || instead of case, but that would cause problems in the event that the user had set a boolean preference to false.

    Edit: N.B. I don't know of a good way to update the defaults in a rails app without restarting the server.