diff --git a/app/models/spree/preference.rb b/app/models/spree/preference.rb index da6f5464f1..145863dab3 100644 --- a/app/models/spree/preference.rb +++ b/app/models/spree/preference.rb @@ -1,37 +1,39 @@ # frozen_string_literal: true -class Spree::Preference < ActiveRecord::Base - serialize :value +module Spree + class Preference < ActiveRecord::Base + serialize :value - validates :key, presence: true - validates :value_type, presence: true + validates :key, presence: true + validates :value_type, presence: true - scope :valid, -> { where(Spree::Preference.arel_table[:key].not_eq(nil)).where(Spree::Preference.arel_table[:value_type].not_eq(nil)) } + scope :valid, -> { where(Spree::Preference.arel_table[:key].not_eq(nil)).where(Spree::Preference.arel_table[:value_type].not_eq(nil)) } - # The type conversions here should match - # the ones in spree::preferences::preferrable#convert_preference_value - def value - if self[:value_type].present? - case self[:value_type].to_sym - when :string, :text - self[:value].to_s - when :password - self[:value].to_s - when :decimal - BigDecimal(self[:value].to_s).round(2, BigDecimal::ROUND_HALF_UP) - when :integer - self[:value].to_i - when :boolean - (self[:value].to_s =~ /^[t|1]/i) != nil + # The type conversions here should match + # the ones in spree::preferences::preferrable#convert_preference_value + def value + if self[:value_type].present? + case self[:value_type].to_sym + when :string, :text + self[:value].to_s + when :password + self[:value].to_s + when :decimal + BigDecimal(self[:value].to_s).round(2, BigDecimal::ROUND_HALF_UP) + when :integer + self[:value].to_i + when :boolean + (self[:value].to_s =~ /^[t|1]/i) != nil + else + self[:value].is_a?(String) ? YAML.safe_load(self[:value]) : self[:value] + end else - self[:value].is_a?(String) ? YAML.safe_load(self[:value]) : self[:value] + self[:value] end - else + end + + def raw_value self[:value] end end - - def raw_value - self[:value] - end end diff --git a/app/models/spree/preferences/configuration.rb b/app/models/spree/preferences/configuration.rb index 25216fc899..3c4c9a13b0 100644 --- a/app/models/spree/preferences/configuration.rb +++ b/app/models/spree/preferences/configuration.rb @@ -22,50 +22,52 @@ # a.preferred_color # # -module Spree::Preferences - class Configuration - include Spree::Preferences::Preferable +module Spree + module Preferences + class Configuration + include Spree::Preferences::Preferable - def configure - yield(self) if block_given? - end - - def preference_cache_key(name) - [ENV['RAILS_CACHE_ID'], self.class.name, name].flatten.join('::').underscore - end - - def reset - preferences.each do |name, _value| - set_preference name, preference_default(name) - end - end - - alias :[] :get_preference - alias :[]= :set_preference - - alias :get :get_preference - - def set(*args) - options = args.extract_options! - options.each do |name, value| - set_preference name, value + def configure + yield(self) if block_given? end - if args.size == 2 - set_preference args[0], args[1] + def preference_cache_key(name) + [ENV['RAILS_CACHE_ID'], self.class.name, name].flatten.join('::').underscore end - end - def method_missing(method, *args) - name = method.to_s.gsub('=', '') - if has_preference? name - if method.to_s =~ /=$/ - set_preference(name, args.first) - else - get_preference name + def reset + preferences.each do |name, _value| + set_preference name, preference_default(name) + end + end + + alias :[] :get_preference + alias :[]= :set_preference + + alias :get :get_preference + + def set(*args) + options = args.extract_options! + options.each do |name, value| + set_preference name, value + end + + if args.size == 2 + set_preference args[0], args[1] + end + end + + def method_missing(method, *args) + name = method.to_s.gsub('=', '') + if has_preference? name + if method.to_s =~ /=$/ + set_preference(name, args.first) + else + get_preference name + end + else + super end - else - super end end end diff --git a/app/models/spree/preferences/preferable.rb b/app/models/spree/preferences/preferable.rb index 9242ed1d11..603cec767d 100644 --- a/app/models/spree/preferences/preferable.rb +++ b/app/models/spree/preferences/preferable.rb @@ -10,125 +10,129 @@ # inherited hook will assign a new hash for the subclass definitions # and copy all the definitions allowing the subclass to add # additional defintions without affecting the base -module Spree::Preferences::Preferable - def self.included(base) - base.class_eval do - extend Spree::Preferences::PreferableClassMethods +module Spree + module Preferences + module Preferable + def self.included(base) + base.class_eval do + extend Spree::Preferences::PreferableClassMethods - if respond_to?(:after_create) - after_create(&:save_pending_preferences) + if respond_to?(:after_create) + after_create(&:save_pending_preferences) + end + + if respond_to?(:after_destroy) + after_destroy(&:clear_preferences) + end + end end - if respond_to?(:after_destroy) - after_destroy(&:clear_preferences) + def get_preference(name) + has_preference! name + send self.class.preference_getter_method(name) + end + alias :preferred :get_preference + alias :prefers? :get_preference + + def set_preference(name, value) + has_preference! name + send self.class.preference_setter_method(name), value + end + + def preference_type(name) + has_preference! name + send self.class.preference_type_getter_method(name) + end + + def preference_default(name) + has_preference! name + send self.class.preference_default_getter_method(name) + end + + def preference_description(name) + has_preference! name + send self.class.preference_description_getter_method(name) + end + + def has_preference!(name) + raise NoMethodError, "#{name} preference not defined" unless has_preference? name + end + + def has_preference?(name) + respond_to? self.class.preference_getter_method(name) + end + + def preferences + prefs = {} + methods.grep(/^prefers_.*\?$/).each do |pref_method| + prefs[pref_method.to_s.gsub(/prefers_|\?/, '').to_sym] = send(pref_method) + end + prefs + end + + def prefers?(name) + get_preference(name) + end + + def preference_cache_key(name) + return unless id + + [ENV["RAILS_CACHE_ID"], self.class.name, name, id].join('::').underscore + end + + def save_pending_preferences + return unless @pending_preferences + + @pending_preferences.each do |name, value| + set_preference(name, value) + end + end + + def clear_preferences + preferences.keys.each { |pref| preference_store.delete preference_cache_key(pref) } + end + + private + + def add_pending_preference(name, value) + @pending_preferences ||= {} + @pending_preferences[name] = value + end + + def get_pending_preference(name) + return unless @pending_preferences + + @pending_preferences[name] + end + + def convert_preference_value(value, type) + case type + when :string, :text + value.to_s + when :password + value.to_s + when :decimal + BigDecimal(value.to_s).round(2, BigDecimal::ROUND_HALF_UP) + when :integer + value.to_i + when :boolean + if value.is_a?(FalseClass) || + value.nil? || + value == 0 || + value =~ /^(f|false|0)$/i || + (value.respond_to?(:empty?) && value.empty?) + false + else + true + end + else + value + end + end + + def preference_store + Spree::Preferences::Store.instance end end end - - def get_preference(name) - has_preference! name - send self.class.preference_getter_method(name) - end - alias :preferred :get_preference - alias :prefers? :get_preference - - def set_preference(name, value) - has_preference! name - send self.class.preference_setter_method(name), value - end - - def preference_type(name) - has_preference! name - send self.class.preference_type_getter_method(name) - end - - def preference_default(name) - has_preference! name - send self.class.preference_default_getter_method(name) - end - - def preference_description(name) - has_preference! name - send self.class.preference_description_getter_method(name) - end - - def has_preference!(name) - raise NoMethodError, "#{name} preference not defined" unless has_preference? name - end - - def has_preference?(name) - respond_to? self.class.preference_getter_method(name) - end - - def preferences - prefs = {} - methods.grep(/^prefers_.*\?$/).each do |pref_method| - prefs[pref_method.to_s.gsub(/prefers_|\?/, '').to_sym] = send(pref_method) - end - prefs - end - - def prefers?(name) - get_preference(name) - end - - def preference_cache_key(name) - return unless id - - [ENV["RAILS_CACHE_ID"], self.class.name, name, id].join('::').underscore - end - - def save_pending_preferences - return unless @pending_preferences - - @pending_preferences.each do |name, value| - set_preference(name, value) - end - end - - def clear_preferences - preferences.keys.each { |pref| preference_store.delete preference_cache_key(pref) } - end - - private - - def add_pending_preference(name, value) - @pending_preferences ||= {} - @pending_preferences[name] = value - end - - def get_pending_preference(name) - return unless @pending_preferences - - @pending_preferences[name] - end - - def convert_preference_value(value, type) - case type - when :string, :text - value.to_s - when :password - value.to_s - when :decimal - BigDecimal(value.to_s).round(2, BigDecimal::ROUND_HALF_UP) - when :integer - value.to_i - when :boolean - if value.is_a?(FalseClass) || - value.nil? || - value == 0 || - value =~ /^(f|false|0)$/i || - (value.respond_to?(:empty?) && value.empty?) - false - else - true - end - else - value - end - end - - def preference_store - Spree::Preferences::Store.instance - end end diff --git a/app/models/spree/preferences/preferable_class_methods.rb b/app/models/spree/preferences/preferable_class_methods.rb index b36255c8b5..f6ac02e781 100644 --- a/app/models/spree/preferences/preferable_class_methods.rb +++ b/app/models/spree/preferences/preferable_class_methods.rb @@ -1,85 +1,87 @@ # frozen_string_literal: true -module Spree::Preferences - module PreferableClassMethods - def preference(name, type, *args) - options = args.extract_options! - options.assert_valid_keys(:default, :description) - default = options[:default] - description = options[:description] || name +module Spree + module Preferences + module PreferableClassMethods + def preference(name, type, *args) + options = args.extract_options! + options.assert_valid_keys(:default, :description) + default = options[:default] + description = options[:description] || name - # cache_key will be nil for new objects, then if we check if there - # is a pending preference before going to default - define_method preference_getter_method(name) do - # perference_cache_key will only be nil/false for new records - # - if preference_cache_key(name) - preference_store.get(preference_cache_key(name), default) - else - get_pending_preference(name) || default + # cache_key will be nil for new objects, then if we check if there + # is a pending preference before going to default + define_method preference_getter_method(name) do + # perference_cache_key will only be nil/false for new records + # + if preference_cache_key(name) + preference_store.get(preference_cache_key(name), default) + else + get_pending_preference(name) || default + end + end + alias_method prefers_getter_method(name), preference_getter_method(name) + + define_method preference_setter_method(name) do |value| + value = convert_preference_value(value, type) + if preference_cache_key(name) + preference_store.set preference_cache_key(name), value, type + else + add_pending_preference(name, value) + end + end + alias_method prefers_setter_method(name), preference_setter_method(name) + + define_method preference_default_getter_method(name) do + default + end + + define_method preference_type_getter_method(name) do + type + end + + define_method preference_description_getter_method(name) do + description end end - alias_method prefers_getter_method(name), preference_getter_method(name) - define_method preference_setter_method(name) do |value| - value = convert_preference_value(value, type) - if preference_cache_key(name) - preference_store.set preference_cache_key(name), value, type - else - add_pending_preference(name, value) - end - end - alias_method prefers_setter_method(name), preference_setter_method(name) - - define_method preference_default_getter_method(name) do - default + def remove_preference(name) + remove_method preference_getter_method(name) if method_defined? preference_getter_method(name) + remove_method preference_setter_method(name) if method_defined? preference_setter_method(name) + remove_method prefers_getter_method(name) if method_defined? prefers_getter_method(name) + remove_method prefers_setter_method(name) if method_defined? prefers_setter_method(name) + remove_method preference_default_getter_method(name) if method_defined? preference_default_getter_method(name) + remove_method preference_type_getter_method(name) if method_defined? preference_type_getter_method(name) + remove_method preference_description_getter_method(name) if method_defined? preference_description_getter_method(name) end - define_method preference_type_getter_method(name) do - type + def preference_getter_method(name) + "preferred_#{name}".to_sym end - define_method preference_description_getter_method(name) do - description + def preference_setter_method(name) + "preferred_#{name}=".to_sym end - end - def remove_preference(name) - remove_method preference_getter_method(name) if method_defined? preference_getter_method(name) - remove_method preference_setter_method(name) if method_defined? preference_setter_method(name) - remove_method prefers_getter_method(name) if method_defined? prefers_getter_method(name) - remove_method prefers_setter_method(name) if method_defined? prefers_setter_method(name) - remove_method preference_default_getter_method(name) if method_defined? preference_default_getter_method(name) - remove_method preference_type_getter_method(name) if method_defined? preference_type_getter_method(name) - remove_method preference_description_getter_method(name) if method_defined? preference_description_getter_method(name) - end + def prefers_getter_method(name) + "prefers_#{name}?".to_sym + end - def preference_getter_method(name) - "preferred_#{name}".to_sym - end + def prefers_setter_method(name) + "prefers_#{name}=".to_sym + end - def preference_setter_method(name) - "preferred_#{name}=".to_sym - end + def preference_default_getter_method(name) + "preferred_#{name}_default".to_sym + end - def prefers_getter_method(name) - "prefers_#{name}?".to_sym - end + def preference_type_getter_method(name) + "preferred_#{name}_type".to_sym + end - def prefers_setter_method(name) - "prefers_#{name}=".to_sym - end - - def preference_default_getter_method(name) - "preferred_#{name}_default".to_sym - end - - def preference_type_getter_method(name) - "preferred_#{name}_type".to_sym - end - - def preference_description_getter_method(name) - "preferred_#{name}_description".to_sym + def preference_description_getter_method(name) + "preferred_#{name}_description".to_sym + end end end end diff --git a/app/models/spree/preferences/store.rb b/app/models/spree/preferences/store.rb index 28e9d8bfbd..cb30d31eaa 100644 --- a/app/models/spree/preferences/store.rb +++ b/app/models/spree/preferences/store.rb @@ -8,90 +8,92 @@ require 'singleton' -module Spree::Preferences - class StoreInstance - attr_accessor :persistence +module Spree + module Preferences + class StoreInstance + attr_accessor :persistence - def initialize - @cache = Rails.cache - @persistence = true - end - - def set(key, value, type) - @cache.write(key, value) - persist(key, value, type) - end - - def exist?(key) - @cache.exist?(key) || - should_persist? && Spree::Preference.where(key: key).exists? - end - - def get(key, fallback = nil) - # return the retrieved value, if it's in the cache - # use unless nil? incase the value is actually boolean false - # - unless (val = @cache.read(key)).nil? - return val + def initialize + @cache = Rails.cache + @persistence = true end - if should_persist? - # If it's not in the cache, maybe it's in the database, but - # has been cleared from the cache - - # does it exist in the database? - if Spree::Preference.table_exists? && preference = Spree::Preference.find_by(key: key) - # it does exist, so let's put it back into the cache - @cache.write(preference.key, preference.value) - - # and return the value - return preference.value - end + def set(key, value, type) + @cache.write(key, value) + persist(key, value, type) end - unless fallback.nil? - # cache fallback so we won't hit the db above on - # subsequent queries for the same key + def exist?(key) + @cache.exist?(key) || + should_persist? && Spree::Preference.where(key: key).exists? + end + + def get(key, fallback = nil) + # return the retrieved value, if it's in the cache + # use unless nil? incase the value is actually boolean false # - @cache.write(key, fallback) + unless (val = @cache.read(key)).nil? + return val + end + + if should_persist? + # If it's not in the cache, maybe it's in the database, but + # has been cleared from the cache + + # does it exist in the database? + if Spree::Preference.table_exists? && preference = Spree::Preference.find_by(key: key) + # it does exist, so let's put it back into the cache + @cache.write(preference.key, preference.value) + + # and return the value + return preference.value + end + end + + unless fallback.nil? + # cache fallback so we won't hit the db above on + # subsequent queries for the same key + # + @cache.write(key, fallback) + end + + fallback end - fallback + def delete(key) + @cache.delete(key) + destroy(key) + end + + def clear_cache + @cache.clear + end + + private + + def persist(cache_key, value, type) + return unless should_persist? + + preference = Spree::Preference.where(key: cache_key).first_or_initialize + preference.value = value + preference.value_type = type + preference.save + end + + def destroy(cache_key) + return unless should_persist? + + preference = Spree::Preference.find_by(key: cache_key) + preference&.destroy + end + + def should_persist? + @persistence && Spree::Preference.connected? && Spree::Preference.table_exists? + end end - def delete(key) - @cache.delete(key) - destroy(key) + class Store < StoreInstance + include Singleton end - - def clear_cache - @cache.clear - end - - private - - def persist(cache_key, value, type) - return unless should_persist? - - preference = Spree::Preference.where(key: cache_key).first_or_initialize - preference.value = value - preference.value_type = type - preference.save - end - - def destroy(cache_key) - return unless should_persist? - - preference = Spree::Preference.find_by(key: cache_key) - preference&.destroy - end - - def should_persist? - @persistence && Spree::Preference.connected? && Spree::Preference.table_exists? - end - end - - class Store < StoreInstance - include Singleton end end