system_settings 0.6.1 → 0.9.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.
- checksums.yaml +4 -4
- data/README.md +11 -13
- data/app/assets/config/manifest.js +1 -0
- data/app/assets/stylesheets/system_settings/application.css +227 -0
- data/app/controllers/system_settings/application_controller.rb +2 -6
- data/app/controllers/system_settings/settings_controller.rb +21 -16
- data/app/helpers/system_settings/application_helper.rb +34 -0
- data/app/models/system_settings/application_record.rb +2 -0
- data/app/models/system_settings/boolean_setting.rb +2 -0
- data/app/models/system_settings/configurator.rb +38 -10
- data/app/models/system_settings/decimal_list_setting.rb +8 -0
- data/app/models/system_settings/decimal_setting.rb +8 -0
- data/app/models/system_settings/errors/error.rb +2 -0
- data/app/models/system_settings/errors/not_found_error.rb +3 -1
- data/app/models/system_settings/errors/not_loaded_error.rb +8 -0
- data/app/models/system_settings/errors/settings_read_error.rb +2 -0
- data/app/models/system_settings/integer_list_setting.rb +3 -1
- data/app/models/system_settings/integer_setting.rb +3 -1
- data/app/models/system_settings/list_of_decimals_validator.rb +37 -0
- data/app/models/system_settings/list_of_integers_validator.rb +2 -0
- data/app/models/system_settings/list_of_strings_validator.rb +2 -0
- data/app/models/system_settings/setting.rb +2 -0
- data/app/models/system_settings/string_list_setting.rb +2 -0
- data/app/models/system_settings/string_setting.rb +7 -0
- data/app/models/system_settings/type/decimal_list.rb +42 -0
- data/app/models/system_settings/type/integer_list.rb +10 -15
- data/app/models/system_settings/type/string_list.rb +2 -0
- data/app/views/layouts/system_settings/application.html.erb +21 -0
- data/app/views/system_settings/settings/_common_attributes.html.erb +14 -0
- data/app/views/system_settings/settings/_form.html.erb +18 -0
- data/app/views/system_settings/settings/edit.html.erb +2 -0
- data/app/views/system_settings/settings/index.html.erb +29 -0
- data/app/views/system_settings/settings/show.html.erb +9 -0
- data/config/locales/system_settings.en.yml +27 -1
- data/config/routes.rb +7 -4
- data/lib/system_settings.rb +13 -7
- data/lib/system_settings/engine.rb +6 -13
- data/lib/system_settings/version.rb +3 -1
- metadata +17 -14
- data/app/controllers/system_settings/root_controller.rb +0 -11
- data/app/models/system_settings/pagination.rb +0 -18
- data/frontend/build/asset-manifest.json +0 -11
- data/frontend/build/favicon.ico +0 -0
- data/frontend/build/index.html +0 -1
- data/frontend/build/precache-manifest.cace9a6c696c96461d63a2e3a1cca55e.js +0 -22
- data/frontend/build/service-worker.js +0 -39
- data/frontend/build/static/css/main.003e6dc8.chunk.css +0 -1
- data/frontend/build/static/js/2.42b63415.chunk.js +0 -1
- data/frontend/build/static/js/main.9315e265.chunk.js +0 -1
- data/frontend/build/static/js/runtime~main.a09e9b82.js +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 321c73f1b71d88e67c98191025ac69b6fa58ea6dbbaa838cb5a6eaea6622337a
|
4
|
+
data.tar.gz: 17bd42a54230f37063f618fe2cfebc3875410d3879757e9ed38138990c6a952d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4231c986165f29d944aec79b4cc5239ccc9f7d614ef710ec77e452a238f8579ec3afcf20c09c0701ec49b3a89547ebbfcc3e4f395a71d024b1349fadb8df1cfc
|
7
|
+
data.tar.gz: bab2dd0fbf7b7f5f38ea38e4ebdcb1d732eb0254a2e3278925ac16408cca8d3c05c898137c92e7916c2b4f85c6105a9ad1e1ec5be0e51eb9d8a0fa617ff3fd47
|
data/README.md
CHANGED
@@ -42,10 +42,14 @@ string :default_locale, value: "en"
|
|
42
42
|
integer :default_records_per_page, value: 25
|
43
43
|
integer :remainder_interval_in_hours, value: 48
|
44
44
|
|
45
|
-
#
|
45
|
+
# Decimal values
|
46
|
+
decimal :max_temp, value: 95.2
|
47
|
+
|
48
|
+
# Array type strings, integers and decimals
|
46
49
|
string_list :admin_emails, description: "Will receive alerts"
|
47
50
|
string_list :upload_allowed_extensions, value: ["docx", "pdf", "txt"]
|
48
51
|
integer_list :lucky_numbers, description: "Prime numbers are more effective", value: [2, 3, 5, 11]
|
52
|
+
decimal_list :allowed_multipliers, value: [12.3, 99, BigDecimal("-87")]
|
49
53
|
```
|
50
54
|
|
51
55
|
Load values from `config/system_settings.rb` into database:
|
@@ -93,19 +97,16 @@ If you would like to store your settings somewhere else than `config/system_sett
|
|
93
97
|
|
94
98
|
## Using System Settings in tests
|
95
99
|
|
96
|
-
Your test suite probably clears database before/after every test example. Fortunately is very easy to load fresh settings from configuration file.
|
100
|
+
Your test suite probably clears database before/after every test example. Fortunately is very easy to load fresh settings from configuration file.
|
101
|
+
It can be done by running `SystemSettings.load`. It will persist all loaded settings. But if you would like to persist only a subset of loaded settings run `SystemSettings.load(:one, :two, :three)`.
|
102
|
+
|
97
103
|
And if you modify settings values in test example you can reset to defaults with `SystemSettings.reset_to_defaults`.
|
98
104
|
|
99
105
|
|
100
106
|
## Development
|
101
107
|
|
102
|
-
Required development dependencies:
|
103
|
-
* [Node.js](https://nodejs.org/) - JavaScript runtime
|
104
|
-
* [Yarn](https://yarnpkg.com/) - package manager
|
105
|
-
|
106
108
|
Optional development tools:
|
107
|
-
* [
|
108
|
-
* [direnv](https://direnv.net/) - Unclutter your .profile
|
109
|
+
* [direnv](https://direnv.net/) - Unclutter your .profile
|
109
110
|
|
110
111
|
Required environment variables:
|
111
112
|
* `RAILS_VERSION`
|
@@ -120,16 +121,13 @@ Getting started with development:
|
|
120
121
|
1) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 bundle`
|
121
122
|
2) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails db:create db:migrate`
|
122
123
|
3) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails test`
|
123
|
-
4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails frontend:install`
|
124
|
-
4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails app:system_settings:load`
|
125
|
-
4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 overmind start`
|
126
|
-
|
127
124
|
|
128
125
|
## Build status
|
129
126
|
System Settings is being tested with Rails versions - `5.0`, `5.1`, `5.2`, `6.0`, `rails repo master branch`
|
130
127
|
|
131
128
|
[](https://dev.azure.com/kristsozols/System%20Settings/_build/latest?definitionId=1&branchName=master)
|
132
|
-
|
129
|
+
[](https://codeclimate.com/github/krists/system_settings/maintainability)
|
130
|
+
[](https://codeclimate.com/github/krists/system_settings/test_coverage)
|
133
131
|
|
134
132
|
## License
|
135
133
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets .css
|
@@ -0,0 +1,227 @@
|
|
1
|
+
html {
|
2
|
+
box-sizing: border-box;
|
3
|
+
font-size: 14px;
|
4
|
+
font-family: Arial, Helvetica, sans-serif;
|
5
|
+
overflow-y: scroll;
|
6
|
+
}
|
7
|
+
|
8
|
+
*, *:before, *:after {box-sizing: inherit;}
|
9
|
+
|
10
|
+
body {
|
11
|
+
margin: 0;
|
12
|
+
padding: 0;
|
13
|
+
font-weight: normal;
|
14
|
+
min-height: 100vh;
|
15
|
+
position: relative;
|
16
|
+
display: flex;
|
17
|
+
flex-direction: column;
|
18
|
+
color: #233656;
|
19
|
+
background: white;
|
20
|
+
font-size: 1rem;
|
21
|
+
line-height: 1.5rem;
|
22
|
+
}
|
23
|
+
|
24
|
+
header {
|
25
|
+
border-bottom: 1px solid #e1e1e1;
|
26
|
+
height: 2rem;
|
27
|
+
padding: 0.5rem 0;
|
28
|
+
box-sizing: content-box;
|
29
|
+
background: white;
|
30
|
+
position: sticky;
|
31
|
+
top: 0;
|
32
|
+
width: 100%;
|
33
|
+
}
|
34
|
+
|
35
|
+
main {
|
36
|
+
padding: 3rem 0;
|
37
|
+
}
|
38
|
+
|
39
|
+
header .container,
|
40
|
+
main .container {
|
41
|
+
max-width: 1020px;
|
42
|
+
margin: 0 auto;
|
43
|
+
}
|
44
|
+
|
45
|
+
a { color: #233656; text-decoration: none; }
|
46
|
+
a:hover { text-decoration: underline; }
|
47
|
+
|
48
|
+
.app-name, .app-name:hover, .app-name:active {
|
49
|
+
font-size: 1.5rem;
|
50
|
+
line-height: 2rem;
|
51
|
+
font-weight: bold;
|
52
|
+
user-select: none;
|
53
|
+
text-decoration: none;
|
54
|
+
}
|
55
|
+
|
56
|
+
.sys-name {
|
57
|
+
display: inline-block;
|
58
|
+
background: #f2f2f2;
|
59
|
+
border-radius: 3px;
|
60
|
+
padding: 0 0.5em;
|
61
|
+
font-family: "Courier New", Courier, monospace;
|
62
|
+
font-size: 0.75em;
|
63
|
+
max-width: 100%;
|
64
|
+
}
|
65
|
+
|
66
|
+
table th {
|
67
|
+
text-align: left;
|
68
|
+
}
|
69
|
+
|
70
|
+
.settings-table {
|
71
|
+
width: 100%;
|
72
|
+
table-layout: fixed;
|
73
|
+
white-space: nowrap;
|
74
|
+
user-select: none;
|
75
|
+
}
|
76
|
+
|
77
|
+
.settings-table td:empty:after {
|
78
|
+
content: "-";
|
79
|
+
}
|
80
|
+
|
81
|
+
.settings-table td {
|
82
|
+
overflow: hidden;
|
83
|
+
text-overflow: ellipsis;
|
84
|
+
}
|
85
|
+
|
86
|
+
.settings-table .description { width: 35% }
|
87
|
+
.settings-table .value { width: 25% }
|
88
|
+
|
89
|
+
.settings-table tbody td.no-entries {
|
90
|
+
color: #737373;
|
91
|
+
padding-top: 1rem;
|
92
|
+
margin-bottom: 1rem;
|
93
|
+
}
|
94
|
+
|
95
|
+
.settings-table tfoot td {
|
96
|
+
font-size: 0.8em;
|
97
|
+
padding-top: 1rem;
|
98
|
+
margin-bottom: 1rem;
|
99
|
+
}
|
100
|
+
|
101
|
+
.settings-table .value .value-part, .attribute .value .value-part {
|
102
|
+
max-width: 100%;
|
103
|
+
margin-right: 0.25em;
|
104
|
+
}
|
105
|
+
|
106
|
+
.settings-table .value .value-part:last-child, .attribute .value .value-part:last-child {
|
107
|
+
margin-right: 0;
|
108
|
+
}
|
109
|
+
|
110
|
+
.attribute {
|
111
|
+
display: flex;
|
112
|
+
flex-direction: column;
|
113
|
+
margin-bottom: 1rem;
|
114
|
+
}
|
115
|
+
|
116
|
+
.attribute .name {
|
117
|
+
font-size: 0.8em;
|
118
|
+
color: #737373;
|
119
|
+
user-select: none;
|
120
|
+
}
|
121
|
+
|
122
|
+
.attribute .value {
|
123
|
+
align-self: flex-start;
|
124
|
+
}
|
125
|
+
.attribute .value:empty:after {
|
126
|
+
content: "-";
|
127
|
+
}
|
128
|
+
|
129
|
+
.attribute .field_with_errors .name, .attribute .errors {
|
130
|
+
color: #d01d1d;
|
131
|
+
}
|
132
|
+
.attribute .hint {
|
133
|
+
font-size: 0.8em;
|
134
|
+
display: block;
|
135
|
+
}
|
136
|
+
|
137
|
+
.buttons {
|
138
|
+
border-top: 1px dotted #f2f2f2;
|
139
|
+
padding-top: 1rem;
|
140
|
+
margin-bottom: 1rem;
|
141
|
+
}
|
142
|
+
.buttons > * {
|
143
|
+
margin-right: 0.5rem;
|
144
|
+
}
|
145
|
+
|
146
|
+
button, input[type=submit], input[type=button], a.button {
|
147
|
+
display: inline-block;
|
148
|
+
cursor: pointer;
|
149
|
+
border: none;
|
150
|
+
border-radius: 3px;
|
151
|
+
padding: 0.375rem 0.75rem;
|
152
|
+
font-size: 1rem;
|
153
|
+
line-height: 1.5;
|
154
|
+
user-select: none;
|
155
|
+
white-space: nowrap;
|
156
|
+
}
|
157
|
+
|
158
|
+
button, input[type=submit], input[type=button] {
|
159
|
+
color: #4d4d4d;
|
160
|
+
background-color: #d9d9d9;
|
161
|
+
transition: background-color 0.1s ease-in-out;
|
162
|
+
outline: none;
|
163
|
+
}
|
164
|
+
|
165
|
+
button:focus, button:hover, input[type=submit]:focus, input[type=submit]:hover, input[type=button]:focus, input[type=button]:hover {
|
166
|
+
background-color: #b8b8b8;
|
167
|
+
}
|
168
|
+
|
169
|
+
button:active, input[type=submit]:active, input[type=button]:active {
|
170
|
+
background-color: #828282;
|
171
|
+
}
|
172
|
+
|
173
|
+
a.button {
|
174
|
+
color: #4d4d4d;
|
175
|
+
background-color: transparent;
|
176
|
+
transition: background-color 0.1s ease-in-out;
|
177
|
+
outline: none;
|
178
|
+
text-decoration: none;
|
179
|
+
}
|
180
|
+
|
181
|
+
a.button:focus, a.button:hover {
|
182
|
+
background-color: rgba(0, 0, 0, 0.15);
|
183
|
+
}
|
184
|
+
|
185
|
+
a.button:active {
|
186
|
+
background-color: rgba(0, 0, 0, 0.4);
|
187
|
+
}
|
188
|
+
|
189
|
+
button.primary, input[type=submit].primary, input[type=button].primary, a.button.primary {
|
190
|
+
color: #4d4d4d;
|
191
|
+
background-color: #a6a6a6;
|
192
|
+
transition: background-color 0.1s ease-in-out;
|
193
|
+
outline: none;
|
194
|
+
}
|
195
|
+
|
196
|
+
button.primary:focus, button.primary:hover, input[type=submit].primary:focus, input[type=submit].primary:hover, input[type=button].primary:focus, input[type=button].primary:hover, a.button.primary:focus, a.button.primary:hover {
|
197
|
+
background-color: #8d8d8d;
|
198
|
+
}
|
199
|
+
|
200
|
+
button.primary:active, input[type=submit].primary:active, input[type=button].primary:active, a.button.primary:active {
|
201
|
+
background-color: #646464;
|
202
|
+
}
|
203
|
+
|
204
|
+
input[type=text] {
|
205
|
+
border: none;
|
206
|
+
border-radius: 3px;
|
207
|
+
padding: 0.5em;
|
208
|
+
font-size: 1rem;
|
209
|
+
line-height: normal;
|
210
|
+
color: #4d4d4d;
|
211
|
+
background-color: #e6e6e6;
|
212
|
+
transition: background-color 0.1s ease-in-out;
|
213
|
+
outline: none;
|
214
|
+
box-sizing: content-box;
|
215
|
+
width: auto;
|
216
|
+
min-width: 12ch;
|
217
|
+
max-width: calc(100% - 2em);
|
218
|
+
will-change: width;
|
219
|
+
}
|
220
|
+
|
221
|
+
input[type=text]:focus {
|
222
|
+
background-color: #c4c4c4;
|
223
|
+
}
|
224
|
+
|
225
|
+
input[type=text]:active {
|
226
|
+
background-color: #bfbfbf;
|
227
|
+
}
|
@@ -1,11 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SystemSettings
|
2
4
|
class ApplicationController < ActionController::Base
|
3
5
|
protect_from_forgery with: :exception
|
4
|
-
|
5
|
-
private
|
6
|
-
|
7
|
-
def add_authenticity_token
|
8
|
-
response.headers["Authenticity-Token"] = form_authenticity_token if protect_against_forgery?
|
9
|
-
end
|
10
6
|
end
|
11
7
|
end
|
@@ -1,29 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SystemSettings
|
2
4
|
class SettingsController < SystemSettings::ApplicationController
|
3
|
-
RETURN_ATTRIBUTES = [
|
5
|
+
RETURN_ATTRIBUTES = %w[id name type value description].freeze
|
6
|
+
before_action :set_setting, only: [:edit, :show, :update]
|
4
7
|
|
5
8
|
def index
|
6
|
-
@
|
7
|
-
@settings = SystemSettings::Setting.order(:name).extending(SystemSettings::Pagination).page(params[:page], per_page: params[:per])
|
8
|
-
render json: {
|
9
|
-
items: @settings.map { |s| s.as_json(only: RETURN_ATTRIBUTES) },
|
10
|
-
total_count: @total_count
|
11
|
-
}
|
9
|
+
@settings = SystemSettings::Setting.order(:name)
|
12
10
|
end
|
13
11
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
render json: @setting.as_json(only: RETURN_ATTRIBUTES)
|
18
|
-
end
|
12
|
+
def edit; end
|
13
|
+
|
14
|
+
def show; end
|
19
15
|
|
20
16
|
def update
|
21
|
-
@setting
|
22
|
-
|
23
|
-
render json: @setting.as_json(only: RETURN_ATTRIBUTES)
|
17
|
+
if @setting.update(setting_params)
|
18
|
+
redirect_to setting_path(@setting)
|
24
19
|
else
|
25
|
-
render
|
20
|
+
render :edit
|
26
21
|
end
|
27
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def set_setting
|
27
|
+
@setting = SystemSettings::Setting.find(params[:id])
|
28
|
+
end
|
29
|
+
|
30
|
+
def setting_params
|
31
|
+
params.require(:setting).permit(:value)
|
32
|
+
end
|
28
33
|
end
|
29
34
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SystemSettings::ApplicationHelper
|
2
|
+
SEPARATOR = ";".freeze
|
3
|
+
|
4
|
+
def format_value(value)
|
5
|
+
if value.respond_to?(:each)
|
6
|
+
capture do
|
7
|
+
value.each do |v|
|
8
|
+
concat content_tag(:span, v, class: "value-part")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
else
|
12
|
+
value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def format_value_for_form(record)
|
17
|
+
case record
|
18
|
+
when SystemSettings::StringListSetting
|
19
|
+
record.value.map { |v| v.gsub(SEPARATOR, "\\#{SEPARATOR}") }.join(SEPARATOR)
|
20
|
+
when SystemSettings::IntegerListSetting, SystemSettings::DecimalListSetting
|
21
|
+
record.value.join(SEPARATOR)
|
22
|
+
else
|
23
|
+
record.value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def display_settings_file_path
|
28
|
+
if SystemSettings.settings_file_path.to_s.include?(Rails.root.to_s)
|
29
|
+
Pathname.new(SystemSettings.settings_file_path).relative_path_from(Rails.root)
|
30
|
+
else
|
31
|
+
SystemSettings.settings_file_path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SystemSettings
|
2
4
|
class Configurator
|
3
5
|
class << self
|
@@ -53,20 +55,33 @@ module SystemSettings
|
|
53
55
|
add(name, SystemSettings::BooleanSetting, value: value, description: description, &blk)
|
54
56
|
end
|
55
57
|
|
56
|
-
def
|
58
|
+
def decimal(name, value: nil, description: nil, &blk)
|
59
|
+
add(name, SystemSettings::DecimalSetting, value: value, description: description, &blk)
|
60
|
+
end
|
61
|
+
|
62
|
+
def decimal_list(name, value: nil, description: nil, &blk)
|
63
|
+
add(name, SystemSettings::DecimalListSetting, value: value || [], description: description, &blk)
|
64
|
+
end
|
65
|
+
|
66
|
+
def persist(only: [])
|
57
67
|
SystemSettings.instrument("system_settings.persist", items: @items) do |payload|
|
58
68
|
if settings_table_exists?
|
59
69
|
SystemSettings::Setting.transaction do
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
70
|
+
if only.empty?
|
71
|
+
@items.each { |item| create_or_update_item(item) }
|
72
|
+
else
|
73
|
+
only.each do |wanted_name|
|
74
|
+
item = @items.find { |i| i[:name] == wanted_name } || begin
|
75
|
+
loaded_names = @items.empty? ? "(none)" : @items.map{ |i| i[:name] }.join("\n")
|
76
|
+
message = <<~MESSAGE.strip
|
77
|
+
Couldn't persist system setting #{wanted_name}. There are no items by this name. Could it be a typo?
|
78
|
+
|
79
|
+
Configurator has loaded following items:
|
80
|
+
#{loaded_names}
|
81
|
+
MESSAGE
|
82
|
+
raise(SystemSettings::Errors::NotLoadedError, message)
|
67
83
|
end
|
68
|
-
|
69
|
-
entry[:class].create!(name: entry[:name], value: entry[:value], description: entry[:description])
|
84
|
+
create_or_update_item(item)
|
70
85
|
end
|
71
86
|
end
|
72
87
|
end
|
@@ -104,5 +119,18 @@ module SystemSettings
|
|
104
119
|
value = value.call if value.is_a?(Proc)
|
105
120
|
@items.push(name: name, class: class_const, value: value, description: description)
|
106
121
|
end
|
122
|
+
|
123
|
+
def create_or_update_item(item)
|
124
|
+
persisted_record = SystemSettings::Setting.find_by(name: item[:name])
|
125
|
+
if persisted_record
|
126
|
+
if persisted_record.class == item[:class]
|
127
|
+
persisted_record.update!(description: item[:description])
|
128
|
+
else
|
129
|
+
warn "SystemSettings: Type mismatch detected! Previously #{item[:name]} had type #{persisted_record.class.name} but you are loading #{item[:class].name}"
|
130
|
+
end
|
131
|
+
else
|
132
|
+
item[:class].create!(name: item[:name], value: item[:value], description: item[:description])
|
133
|
+
end
|
134
|
+
end
|
107
135
|
end
|
108
136
|
end
|