# # TODO: would be great to support something like this: # NetzkePreference["name"].merge!({:a => 1, :b => 2}) # if NetzkePreference["name"] returns a hash # or # NetzkePreference["name"] << 2 # if NetzkePreference["name"] returns an array # etc # class NetzkePreference < ActiveRecord::Base belongs_to :user belongs_to :role ELEMENTARY_CONVERTION_METHODS= {'Fixnum' => 'to_i', 'String' => 'to_s', 'Float' => 'to_f', 'Symbol' => 'to_sym'} def self.widget_name=(value) @@widget_name = value end def self.widget_name @@widget_name ||= nil end def normalized_value klass = read_attribute(:pref_type) norm_value = read_attribute(:value) case klass when nil then r = norm_value # do not cast when 'Boolean' then r = norm_value == 'false' ? false : (norm_value == 'true' || norm_value) when 'NilClass' then r = nil when 'Array', 'Hash' then r = ActiveSupport::JSON.decode(norm_value) else r = norm_value.send(ELEMENTARY_CONVERTION_METHODS[klass]) end r end def normalized_value=(new_value) case new_value.class.name when "Array" then write_attribute(:value, new_value.to_json) when "Hash" then write_attribute(:value, new_value.to_json) else write_attribute(:value, new_value.to_s) end write_attribute(:pref_type, [TrueClass, FalseClass].include?(new_value.class) ? 'Boolean' : new_value.class.to_s) end def self.[](pref_name) pref_name = normalize_preference_name(pref_name) pref = self.pref_to_read(pref_name) pref && pref.normalized_value end def self.[]=(pref_name, new_value) pref_name = normalize_preference_name(pref_name) pref = self.pref_to_write(pref_name) # if assigning nil, simply delete the eventually found preference if new_value.nil? pref && pref.destroy else # pref ||= self.new(conditions(pref_name)) pref.normalized_value = new_value pref.save! end end # Overwrite pref_to_read, pref_to_write methods, and find_all_for_widget if you want a different way of # identifying the proper preference based on your own authorization strategy. # # The default strategy is: # 1) if no masq_user or masq_role defined # pref_to_read will search for the preference for user first, then for user's role # pref_to_write will always find or create a preference for the current user (never for its role) # 2) if masq_user or masq_role is defined # pref_to_read and pref_to_write will always take the masquerade into account, e.g. reads/writes will go to # the user/role specified # def self.pref_to_read(name) name = name.to_s session = Netzke::Base.session cond = {:name => name, :widget_name => self.widget_name} if session[:masq_user] # first, get the prefs for this user it they exist res = self.find(:first, :conditions => cond.merge({:user_id => session[:masq_user]})) # if it doesn't exist, get them for the user's role user = User.find(session[:masq_user]) res ||= self.find(:first, :conditions => cond.merge({:role_id => user.role.id})) elsif session[:masq_role] res = self.find(:first, :conditions => cond.merge({:role_id => session[:masq_role]})) elsif session[:netzke_user_id] user = User.find(session[:netzke_user_id]) res = self.find(:first, :conditions => cond.merge({:user_id => user.id})) res ||= self.find(:first, :conditions => cond.merge({:role_id => user.role.id})) else res = self.find(:first, :conditions => cond) end res end def self.pref_to_write(name) name = name.to_s session = Netzke::Base.session cond = {:name => name, :widget_name => self.widget_name} if session[:masq_user] cond.merge!({:user_id => session[:masq_user]}) res = self.find(:first, :conditions => cond) res ||= self.new(cond) elsif session[:masq_role] # first, delete all the corresponding preferences for the users that have this role Role.find(session[:masq_role]).users.each do |u| self.delete_all(cond.merge({:user_id => u.id})) end cond.merge!({:role_id => session[:masq_role]}) res = self.find(:first, :conditions => cond) res ||= self.new(cond) elsif session[:netzke_user_id] res = self.find(:first, :conditions => cond.merge({:user_id => session[:netzke_user_id]})) res ||= self.new(cond.merge({:user_id => session[:netzke_user_id]})) else res = self.find(:first, :conditions => cond) res ||= self.new(cond) end res end def self.find_all_for_widget(name) session = Netzke::Base.session cond = {:widget_name => name} if session[:masq_user] || session[:masq_role] cond.merge!({:user_id => session[:masq_user], :role_id => session[:masq_role]}) res = self.find(:all, :conditions => cond) elsif session[:netzke_user_id] user = User.find(session[:netzke_user_id]) res = self.find(:all, :conditions => cond.merge({:user_id => session[:netzke_user_id]})) res += self.find(:all, :conditions => cond.merge({:role_id => user.role.try(:id)})) else res = self.find(:all, :conditions => cond) end res end def self.delete_all_for_widget(name) self.destroy(find_all_for_widget(name)) end private def self.normalize_preference_name(name) name.to_s.gsub(".", "__").gsub("/", "__") end end