module HasSettings module ActiveRecordExtension module ClassMethods def has_settings(&block) settings_class = HasSettings.ensure_settings_class(self) settings_class.instance_eval(&block) has_many :settings, :class_name => settings_class.name, :dependent => :destroy do def build(*setting_names) setting_names.each do |setting_name| self << proxy_reflection.klass.new(:name => setting_name.to_s) end end # Define the settings query methods, e.g. +account.settings.wiffle?+ settings_class.list.each do |key| # The query method, does this account have a given setting? account.settings.wiffle? define_method "#{key}?" do any? { |setting| setting.name.to_sym == key } end # The finder method which returns the setting if present, otherwise a new instance, allows # non-destructive create and delete operations: # # account.settings.wiffle.destroy # account.settings.wiffle.create # define_method "#{key}" do instance = detect { |setting| setting.name.to_sym == key } instance ||= settings_class.new(@owner.class.name.underscore.to_sym => @owner, :name => key.to_s) end end end include HasSettings::ActiveRecordExtension::InstanceMethods alias_method_chain :update_attributes, :settings alias_method_chain :update_attributes!, :settings end end module InstanceMethods # Allows you to check for multiple features like account.settings?(:suggestions, :suggestions_on_web) def settings?(*setting_names) setting_names.all? { |setting_name| settings.send("#{setting_name}?") } end def update_attributes_with_settings(attributes) update_settings_attributes(attributes) update_attributes_without_settings(attributes) end def update_attributes_with_settings!(attributes) update_settings_attributes(attributes) update_attributes_without_settings!(attributes) end private def update_settings_attributes(attributes) if attributes && settings_attributes = attributes.delete(:settings) settings_attributes.each do |setting_name, value| setting = settings.send(setting_name) if setting.protected? logger.warn("Someone tried to mass update the protected #{setting_name} setting") else if value == '1' || value == true setting.create else setting.destroy end end end settings.reset end end end def self.included(receiver) receiver.extend(ClassMethods) end end end ActiveRecord::Base.class_eval do include HasSettings::ActiveRecordExtension end