class SettingEntry < ApplicationRecord include Versions validates :code, presence: true, uniqueness: true, format: { with: /\A([a-z])[a-z|_]+[a-z]\z/ } validates :format, presence: true validates :group, presence: true validate :validate_value_format validate :validate_code_is_not_using_reserved_name before_update :replace_boolean_nil_with_false VALUE_FORMATS = { string: :string_format, integer: :integer_format, float: :float_format, boolean: :boolean_format, hash: :hash_format, array: :array_format, }.with_indifferent_access.freeze def retrieve method = VALUE_FORMATS[format] return false if self.format == 'boolean' && value.blank? return if value.blank? send(method) end def self.with_group(group_name) SettingEntry.order(id: :asc).where(group: group_name) end # rubocop:disable Style/MethodMissingSuper # rubocop:disable Style/MissingRespondToMissing def self.method_missing(method, *args) super(method, *args) rescue NoMethodError get_or_set(method.to_s, args[0]) end # rubocop:enable Style/MissingRespondToMissing # rubocop:enable Style/MethodMissingSuper def self.get_or_set(method_name, arg) if method_name[-1] == '=' SettingEntry.find_by!(code: method_name.sub('=', '')).update(value: arg.to_s) else stg = SettingEntry.find_by(code: method_name) stg ? stg.retrieve : nil end end # Hooks def replace_boolean_nil_with_false return unless self.format == 'boolean' return if value == 'true' self.value = 'false' end def validate_code_is_not_using_reserved_name disallowed = [] ActiveRecord::Base.instance_methods.sort.each { |m| disallowed << m.to_s } errors.add(:code, :invalid) if disallowed.include? code end def validate_value_format formats = VALUE_FORMATS.with_indifferent_access errors.add(:format, :invalid) unless formats.keys.any? format end def string_format value end def integer_format value.to_i end def float_format value.to_f end def boolean_format value == 'true' end def hash_format JSON.parse(value) end def array_format JSON.parse(value).to_a end end