activeadmin_settings_cached 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,8 @@ module ActiveadminSettingsCached
4
4
  class Model
5
5
  include ::ActiveModel::Model
6
6
 
7
+ NUMERIC_TYPES = %i[integer float big_decimal].freeze
8
+
7
9
  attr_reader :attributes
8
10
 
9
11
  def initialize(args = {})
@@ -13,71 +15,68 @@ module ActiveadminSettingsCached
13
15
  assign_attributes(merge_attributes(args))
14
16
  end
15
17
 
16
- def field_name(settings_name)
17
- has_key? ? "#{attributes[:key]}.#{settings_name}" : settings_name
18
+ # Editable fields grouped by rails-settings-cached scope
19
+ def fields_by_scope
20
+ fields.group_by { |field| field[:scope] }
18
21
  end
19
22
 
20
- def field_options(settings_name, key_name)
21
- default_value = defaults[settings_name]
22
- value = settings[key_name]
23
-
24
- input_opts = if default_value.is_a?(Array)
25
- {
26
- collection: default_value,
27
- selected: value,
28
- }
29
- elsif (default_value.is_a?(TrueClass) || default_value.is_a?(FalseClass)) &&
30
- display[settings_name].to_s == 'boolean'
31
- {
32
- input_html: { checked: value }, label: '', checked_value: 'true', unchecked_value: 'false'
33
- }
34
- else
35
- {
36
- input_html: { value: value, placeholder: default_value },
37
- }
38
- end
23
+ def fields
24
+ settings_model.editable_keys.map { |key| settings_model.get_field(key) }.select do |field|
25
+ scopes.nil? || scopes.include?(field[:scope])
26
+ end
27
+ end
39
28
 
40
- { as: display[settings_name], label: false }
41
- .merge!(input_opts)
29
+ def keys
30
+ fields.map { |field| field[:key] }
42
31
  end
43
32
 
44
- def settings
45
- data = has_key? ? load_settings_by_key : load_settings
46
- return unless data
33
+ def field_options(key)
34
+ field = settings_model.get_field(key)
35
+ options = field[:options] || {}
36
+ input_html = { value: form_value(key), placeholder: format_value(field[:type], default(field)) }
47
37
 
48
- ::ActiveSupport::OrderedHash[data.to_a.sort { |a, b| a.first <=> b.first }]
49
- end
38
+ input_opts = if options[:option_values]
39
+ { as: :select, collection: options[:option_values], selected: value(key), include_blank: false }
40
+ else
41
+ case field[:type]
42
+ when :boolean
43
+ # Formtastic nests the checkbox into its label, so blank it
44
+ { as: :boolean, label: '', input_html: { checked: value(key) },
45
+ checked_value: 'true', unchecked_value: 'false' }
46
+ when :array, :hash
47
+ { as: :text, input_html: input_html.merge(rows: 5) }
48
+ when *NUMERIC_TYPES
49
+ { as: :number, input_html: input_html }
50
+ else
51
+ { as: :string, input_html: input_html }
52
+ end
53
+ end
50
54
 
51
- def defaults
52
- settings_model.respond_to?(:defaults) ?
53
- settings_model.defaults :
54
- ::RailsSettings::Default
55
- end
55
+ input_opts[:hint] = options[:help_text] if options[:help_text]
56
+ input_opts[:as] = display[key] if display[key]
56
57
 
57
- def defaults_keys
58
- settings_model.respond_to?(:defaults) ?
59
- settings_model.defaults.keys :
60
- ::RailsSettings::Default.instance.keys
58
+ { label: false }.merge(input_opts)
61
59
  end
62
60
 
63
- def display
64
- attributes[:display]
61
+ def value(key)
62
+ settings_model.public_send(key)
65
63
  end
66
64
 
67
- def [](param)
68
- settings_model[param]
65
+ # Value as rendered in the form, used to detect changes on save
66
+ def form_value(key)
67
+ format_value(settings_model.get_field(key)[:type], value(key))
69
68
  end
70
69
 
71
- def []=(param, value)
72
- settings_model[param] = value
70
+ def changed?(key, input)
71
+ normalize(input) != normalize(form_value(key))
73
72
  end
74
73
 
75
74
  def save(key, value)
76
- if has_key?
77
- settings_model.merge!(attributes[:key], { clean_key(key) => value })
78
- else
79
- self[key] = value
80
- end
75
+ settings_model.public_send("#{key}=", value)
76
+ end
77
+
78
+ def display
79
+ attributes[:display]
81
80
  end
82
81
 
83
82
  def persisted?
@@ -86,22 +85,29 @@ module ActiveadminSettingsCached
86
85
 
87
86
  alias_method :to_hash, :attributes
88
87
 
89
- protected
88
+ private
90
89
 
91
- def load_settings
92
- settings_model.public_send(meth, attributes[:starting_with])
90
+ def scopes
91
+ Array(attributes[:scope]).map(&:to_sym).presence
93
92
  end
94
93
 
95
- def load_settings_by_key
96
- self[attributes[:key]]
94
+ def default(field)
95
+ field[:default].is_a?(Proc) ? field[:default].call : field[:default]
97
96
  end
98
97
 
99
- def has_key?
100
- attributes[:key].present?
98
+ def format_value(type, value)
99
+ case type
100
+ when :array
101
+ Array(value).join("\n")
102
+ when :hash
103
+ value.blank? ? '' : value.to_hash.deep_stringify_keys.to_yaml.sub(/\A---\n/, '')
104
+ else
105
+ value.to_s
106
+ end
101
107
  end
102
108
 
103
- def clean_key(key)
104
- key.is_a?(Symbol) ? key : "#{key.sub("#{attributes[:key]}.", '')}"
109
+ def normalize(value)
110
+ value.to_s.gsub("\r\n", "\n").strip
105
111
  end
106
112
 
107
113
  def assign_attributes(args = {})
@@ -110,8 +116,7 @@ module ActiveadminSettingsCached
110
116
 
111
117
  def default_attributes
112
118
  {
113
- starting_with: nil,
114
- key: nil,
119
+ scope: nil,
115
120
  model_name: ::ActiveadminSettingsCached.config.model_name,
116
121
  display: ::ActiveadminSettingsCached.config.display
117
122
  }
@@ -126,13 +131,5 @@ module ActiveadminSettingsCached
126
131
  def settings_model
127
132
  attributes[:model_name]
128
133
  end
129
-
130
- def meth
131
- if Rails.version >= '4.1.0'
132
- :get_all
133
- else
134
- :all
135
- end
136
- end
137
134
  end
138
135
  end
@@ -4,11 +4,10 @@ module ActiveadminSettingsCached
4
4
  module Options
5
5
  VALID_OPTIONS = [
6
6
  :model_name,
7
- :starting_with,
7
+ :scope,
8
8
  :template,
9
9
  :template_object,
10
10
  :display,
11
- :key,
12
11
  :title,
13
12
  :after_save
14
13
  ].freeze
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveadminSettingsCached
4
- VERSION = '2.2.0'
4
+ VERSION = '3.0.0'.freeze
5
5
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'activeadmin_settings_cached/model'
4
+ require 'activeadmin_settings_cached/options'
5
+ require 'activeadmin_settings_cached/dsl'
3
6
  require 'activeadmin_settings_cached/engine'
4
7
 
5
8
  module ActiveadminSettingsCached
data/spec/model_spec.rb CHANGED
@@ -9,165 +9,120 @@ RSpec.describe ActiveadminSettingsCached::Model do
9
9
  end
10
10
  end
11
11
 
12
- before(:all) do
13
- Setting.merge!('some', {
14
- 'first_setting' => 'CCC',
15
- 'second_setting' => true
16
- })
12
+ before do
13
+ ActiveadminSettingsCached.config.display = {}
17
14
  end
18
15
 
19
- let(:all_options) do
20
- {
21
- model_name: 'Setting',
22
- starting_with: 'base.',
23
- key: nil,
24
- display: {'base.first_setting' => 'string', 'base.second_setting' => 'boolean'}
25
- }
26
- end
27
-
28
- let(:key_options) do
29
- {
30
- model_name: 'Setting',
31
- starting_with: nil,
32
- key: 'some',
33
- display: {'some.first_setting' => 'string', 'base.second_setting' => 'boolean'}
34
- }
35
- end
16
+ subject(:object) { described_class.new(options) }
36
17
 
37
- let(:no_options) do
38
- {}
39
- end
18
+ let(:options) { { model_name: 'Setting', scope: :base, display: { 'title' => 'text' } } }
40
19
 
41
20
  context '#attributes' do
42
- before do
43
- ActiveadminSettingsCached.config.display = {}
44
- end
45
-
46
21
  it 'set options' do
47
- object = described_class.new(all_options)
48
22
  expect(object.attributes).to eq({
49
- starting_with: all_options[:starting_with],
50
- key: nil,
51
- model_name: Setting,
52
- display: all_options[:display]
53
- })
23
+ scope: :base,
24
+ model_name: Setting,
25
+ display: { 'title' => 'text' }
26
+ })
54
27
  end
55
28
 
56
- it 'set default options' do
57
- object = described_class.new(no_options)
58
- expect(object.attributes).to eq({
59
- starting_with: nil,
60
- key: nil,
61
- model_name: Setting,
62
- display: {}
63
- })
64
- end
29
+ context 'without options' do
30
+ let(:options) { {} }
65
31
 
66
- it 'set key options' do
67
- object = described_class.new(key_options)
68
- expect(object.attributes).to eq({
69
- starting_with: nil,
70
- key: key_options[:key],
71
- model_name: Setting,
72
- display: key_options[:display]
73
- })
32
+ it 'set default options' do
33
+ expect(object.attributes).to eq({
34
+ scope: nil,
35
+ model_name: Setting,
36
+ display: {}
37
+ })
38
+ end
74
39
  end
75
40
  end
76
41
 
77
- context '#field_name' do
78
- it 'with keyed name' do
79
- object = described_class.new(key_options)
80
- expect(object.field_name('first_setting')).to eq('some.first_setting')
42
+ context '#keys' do
43
+ it 'returns editable keys of scope' do
44
+ expect(object.keys).to eq %w[title captcha_enabled user_limit tax_rate default_locale]
81
45
  end
82
46
 
83
- it 'with normal name' do
84
- object = described_class.new(all_options)
85
- expect(object.field_name('base.first_setting')).to eq('base.first_setting')
47
+ context 'with several scopes' do
48
+ let(:options) { { scope: %i[base second] } }
49
+
50
+ it { expect(object.keys).to include('title', 'admin_emails') }
51
+ it { expect(object.keys).not_to include('app_name', 'secret') }
52
+ end
53
+
54
+ context 'without scope' do
55
+ let(:options) { {} }
56
+
57
+ it { expect(object.keys).to include('app_name', 'title', 'admin_emails') }
58
+ it { expect(object.keys).not_to include('secret') }
86
59
  end
87
60
  end
88
61
 
89
- context '#field_options' do
90
- it 'with default element' do
91
- object = described_class.new(all_options)
92
- expect(object.field_options('base.first_setting', 'base.first_setting')).to eq({as: 'string',
93
- label: false,
94
- input_html: {value: 'AAA', placeholder: 'AAA'}
95
- })
62
+ context '#fields_by_scope' do
63
+ let(:options) { {} }
64
+
65
+ it 'groups fields' do
66
+ expect(object.fields_by_scope.keys).to eq [nil, :base, :second]
96
67
  end
68
+ end
69
+
70
+ context '#field_options' do
71
+ let(:options) { {} }
97
72
 
98
- it 'with keyed element' do
99
- object = described_class.new(key_options)
100
- expect(object.field_options('some.first_setting', 'first_setting')).to eq({as: 'string',
101
- label: false,
102
- input_html: {value: 'CCC', placeholder: 'AAA'}
103
- })
73
+ it 'with string element' do
74
+ expect(object.field_options('app_name')).to eq(as: :string, label: false,
75
+ input_html: { value: 'AAA', placeholder: 'AAA' })
104
76
  end
105
77
 
106
- it 'with array element' do
107
- object = described_class.new(all_options.merge({display: {'base.first_setting' => 'string',
108
- 'base.second_setting' => 'boolean',
109
- 'base.six_setting' => 'array'}}))
110
- expect(object.field_options('base.six_setting', 'base.six_setting')).to eq({as: 'array',
111
- label: false,
112
- collection: %w(a b),
113
- selected: %w(a b)
114
- })
78
+ it 'with number element' do
79
+ expect(object.field_options('user_limit')).to eq(as: :number, label: false,
80
+ input_html: { value: '5', placeholder: '5' })
115
81
  end
116
82
 
117
83
  it 'with boolean element' do
118
- object = described_class.new(all_options)
119
- expect(object.field_options('base.second_setting', 'base.second_setting')).to eq({as: 'boolean',
120
- label: '',
121
- input_html: {checked: true},
122
- checked_value: 'true',
123
- unchecked_value: 'false'
124
- })
84
+ expect(object.field_options('captcha_enabled')).to eq(as: :boolean, label: '',
85
+ input_html: { checked: true },
86
+ checked_value: 'true', unchecked_value: 'false')
125
87
  end
126
- end
127
88
 
128
- context '#settings' do
129
- it 'normal settings' do
130
- object = described_class.new(all_options)
131
- expect(object.settings).to eq(Setting.get_all('base.'))
89
+ it 'with select element' do
90
+ expect(object.field_options('default_locale')).to eq(as: :select, label: false, collection: %w[en de ru],
91
+ selected: 'en', include_blank: false,
92
+ hint: 'Interface language')
132
93
  end
133
94
 
134
- it 'settings by key' do
135
- object = described_class.new(key_options)
136
- expect(object.settings).to eq(Setting['some'])
95
+ it 'with array element' do
96
+ expect(object.field_options('admin_emails')).to eq(as: :text, label: false,
97
+ input_html: { value: "a@example.com\nb@example.com",
98
+ placeholder: "a@example.com\nb@example.com",
99
+ rows: 5 })
137
100
  end
138
- end
139
101
 
140
- context '#save' do
141
- it 'normal settings' do
142
- object = described_class.new(all_options)
143
- object.save('base.first_setting', 'DDD')
144
- expect(Setting['base.first_setting']).to eq('DDD')
102
+ it 'with hash element' do
103
+ expect(object.field_options('notification_options')[:input_html][:value]).to eq("send_all: true\n")
145
104
  end
146
105
 
147
- it 'settings by key' do
148
- object = described_class.new(key_options)
149
- object.save('some.first_setting', 'LLL')
150
- expect(Setting['some']['first_setting']).to eq('LLL')
106
+ context 'with display option' do
107
+ let(:options) { { display: { title: :text } } }
108
+
109
+ it { expect(object.field_options('title')[:as]).to eq :text }
151
110
  end
152
111
  end
153
112
 
154
- context '#defaults' do
155
- it 'normal defaults' do
156
- object = described_class.new(all_options)
157
- expect(object.defaults).to eq(RailsSettings::Default)
158
- end
113
+ context '#changed?' do
114
+ let(:options) { {} }
159
115
 
160
- it 'old defaults' do
161
- allow(Setting).to receive(:defaults).and_return(RailsSettings::Default.instance)
162
- object = described_class.new(all_options)
163
- expect(object.defaults).to be_an_instance_of(RailsSettings::Default)
164
- end
116
+ it { expect(object.changed?('user_limit', '5')).to eq false }
117
+ it { expect(object.changed?('user_limit', '6')).to eq true }
118
+ it { expect(object.changed?('captcha_enabled', 'true')).to eq false }
119
+ it { expect(object.changed?('admin_emails', "a@example.com\r\nb@example.com\r\n")).to eq false }
165
120
  end
166
121
 
167
- context '#defaults_keys' do
168
- it 'normal defaults keys' do
169
- object = described_class.new(all_options)
170
- expect(object.defaults_keys).to eq(RailsSettings::Default.instance.keys)
122
+ context '#save' do
123
+ it 'saves value' do
124
+ object.save('user_limit', '10')
125
+ expect(Setting.user_limit).to eq 10
171
126
  end
172
127
  end
173
128