From 6bdc13b33d8d8d2052d029ac8f99ad0f62df6211 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 31 Aug 2007 17:45:32 +0000 Subject: [PATCH] Added cache for application settings (Setting model). Once the values are cached, only one database query is done at each user request (to check if the cache is still valid). git-svn-id: http://redmine.rubyforge.org/svn/trunk@685 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/application.rb | 1 + app/models/setting.rb | 45 ++++++++++++++++++----- db/migrate/065_add_settings_updated_on.rb | 11 ++++++ 3 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 db/migrate/065_add_settings_updated_on.rb diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 1bb2eac07..b1e2b3d73 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -32,6 +32,7 @@ class ApplicationController < ActionController::Base end def user_setup + Setting.check_cache if session[:user_id] # existing session User.current = User.find(session[:user_id]) diff --git a/app/models/setting.rb b/app/models/setting.rb index ecca01c28..c09b4bdb3 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -23,25 +23,28 @@ class Setting < ActiveRecord::Base validates_uniqueness_of :name validates_inclusion_of :name, :in => @@available_settings.keys validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting| @@available_settings[setting.name]['format'] == 'int' } - - def self.get(name) - name = name.to_s - setting = find_by_name(name) - setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name - setting - end - + + # Hash used to cache setting values + @cached_settings = {} + @cached_cleared_on = Time.now + + # Returns the value of the setting named name def self.[](name) - get(name).value + value = @cached_settings[name] + value ? value : (@cached_settings[name] = find_or_default(name).value) end def self.[]=(name, value) - setting = get(name) + setting = find_or_default(name) setting.value = (value ? value.to_s : "") + @cached_settings[name] = nil setting.save setting.value end + # Defines getter and setter for each setting + # Then setting values can be read using: Setting.some_setting_name + # or set using Setting.some_setting_name = "some value" @@available_settings.each do |name, params| src = <<-END_SRC def self.#{name} @@ -58,4 +61,26 @@ class Setting < ActiveRecord::Base END_SRC class_eval src, __FILE__, __LINE__ end + + # Checks if settings have changed since the values were read + # and clears the cache hash if it's the case + # Called once per request + def self.check_cache + settings_updated_on = Setting.maximum(:updated_on) + if settings_updated_on && @cached_cleared_on <= settings_updated_on + @cached_settings.clear + @cached_cleared_on = Time.now + logger.info "Settings cache cleared." if logger + end + end + +private + # Returns the Setting instance for the setting named name + # (record found in database or new record with default value) + def self.find_or_default(name) + name = name.to_s + raise "There's no setting named #{name}" unless @@available_settings.has_key?(name) + setting = find_by_name(name) + setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name + end end diff --git a/db/migrate/065_add_settings_updated_on.rb b/db/migrate/065_add_settings_updated_on.rb new file mode 100644 index 000000000..8c5fde33b --- /dev/null +++ b/db/migrate/065_add_settings_updated_on.rb @@ -0,0 +1,11 @@ +class AddSettingsUpdatedOn < ActiveRecord::Migration + def self.up + add_column :settings, :updated_on, :timestamp + # set updated_on + Setting.find(:all).each(&:save) + end + + def self.down + remove_column :settings, :updated_on + end +end -- 2.39.5