dynamic_scaffold 0.8.5 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee8bcbe45496d6f41503b4e9ea97197176366b5c57c359be10f48972184df97d
4
- data.tar.gz: 678ba1879ca352131a1c4320e1d9139e8463b8bd25d316222d8e507490d0ae0e
3
+ metadata.gz: 0b9f66a15ba06068661f6bfe62b02db517fbab32f368036939704b54b2ceec8e
4
+ data.tar.gz: f9263e830b2d891eef486565407e89106d0c4afec3d07e6781a6f0b7bf4bd63a
5
5
  SHA512:
6
- metadata.gz: 76e6c4845be245930504f2322121cf03351a79a96b03a4a07526afa0164dd8c4531bd1b0aa3506b664a470c78f4e32d4b521186e1b91c0ff7e047cec12e6dd18
7
- data.tar.gz: d93e3fff877d7facf41b1bfa9f835ba2ce85523d35963df34a537a90ad5f387ed40f113f675ba23e5ab7108ced59373b7ec0c74c3b6fc6f59f42d4062fdf97fb
6
+ metadata.gz: 942fcfb0203d16dc3f549d313eff8fd0e1c0b925155ea33ae1c021c2df16e9f302ada3630e8ba87c1a7a4e5e0b1631edeb812d66d3046f7405426ada1ace2c23
7
+ data.tar.gz: 808f74e475722ae05ae0515a7cdf3b53049adc520cd97cca8bf9f2a8be7eda2c4e63423d93d0b88f7ba5d227089e894d6126192f1afebfb383ad0ba8f808b91d
data/README.md CHANGED
@@ -8,6 +8,7 @@ The Scaffold system which dynamically generates CRUD and sort functions.
8
8
  * Support sort and pagination.
9
9
  * Support image upload with preview.
10
10
  * Support image crop.
11
+ * Support [globalize](https://github.com/globalize/globalize) form fields.
11
12
  * This has the views with the Twitter Bootstrap. Support bootstrap3/4.
12
13
  * Customizable and flexible.
13
14
 
@@ -235,19 +236,6 @@ class ShopController < ApplicationController
235
236
  config.form.item(:collection_check_boxes, :state_ids, State.all, :id, :name)
236
237
  config.form.item(:collection_radio_buttons, :status, Shop.statuses.map{|k, _v| [k, k.titleize]}, :first, :last)
237
238
 
238
- # You can add an image uploader with preview to the form. The save and remove part to the model corresponds to [carrierwave](https://github.com/carrierwaveuploader/carrierwave).
239
- # In the example below, you need to mount the carrierwave uploader on the thumb column of the model.
240
- #
241
- # class Shop < ApplicationRecord
242
- # mount_uploader :thumb, ShopThumbUploader
243
- #
244
- config.form.item(
245
- :carrierwave_image,
246
- :thumb,
247
- preview_max_size: {width: '300px', height: '300px'},
248
- removable: false # If you want to require image, please set removable to false. the default is true.
249
- )
250
-
251
239
  # If you want to display more free form field, use block.
252
240
  # The block is executed in the context of view, so you can call the method of view.
253
241
  config.form.item :block, :free do |form, field|
@@ -292,7 +280,54 @@ class ShopController < ApplicationController
292
280
  end
293
281
  ```
294
282
 
295
- `carrierwave_image` supports [cropper](https://github.com/fengyuanchen/cropperjs). For details, please read [Crop the image](https://github.com/gomo/dynamic_scaffold/wiki/Crop-the-image).
283
+ ##### carrierwave_image
284
+
285
+ You can add an image uploader with preview to the form. It uses [carrierwave](https://github.com/carrierwaveuploader/carrierwave) to save images and associate with records.
286
+
287
+ For example, you mount the carrierwave uploader on the `thumb` column of Shop model.
288
+
289
+ ```rb
290
+ class Shop < ApplicationRecord
291
+ mount_uploader :thumb, ShopThumbUploader
292
+ ```
293
+
294
+ The controller code is as follows.
295
+
296
+ ```rb
297
+ class ShopController < ApplicationController
298
+ include DynamicScaffold::Controller
299
+ dynamic_scaffold Shop do |config|
300
+ ...
301
+ config.form.item(
302
+ :carrierwave_image,
303
+ :thumb,
304
+ preview_max_size: {width: '300px', height: '300px'},
305
+ removable: false # If you want to require image, please set removable to false. the default is true.
306
+ )
307
+ ```
308
+
309
+ The `carrierwave_image` supports [cropper](https://github.com/fengyuanchen/cropperjs) too. For details, please read [Crop the image](https://github.com/gomo/dynamic_scaffold/wiki/Crop-the-image).
310
+
311
+
312
+ ##### globalize_fields
313
+
314
+ We support [globalize](https://github.com/globalize/globalize). Below is the controller code.
315
+
316
+ ```rb
317
+ class ShopController < ApplicationController
318
+ include DynamicScaffold::Controller
319
+ dynamic_scaffold Shop do |config|
320
+ ...
321
+ c.form
322
+ # Each language input field specified in the second argument will generate.
323
+ .item(:globalize_fields, { en: 'English', ja: 'Japanese' }, style: 'width: 78px;')
324
+ # You can specify the type of element to generate to `for` method. it support `:text_field` or `:text_area` for type.
325
+ # Specify the attribute name in the second argument of the `for` method.
326
+ .for(:text_field, :keyword)
327
+ ```
328
+
329
+ Setting the model for globalize_fields with validates is [here](https://github.com/gomo/dynamic_scaffold/wiki/Model-setting-for-globalize).
330
+
296
331
 
297
332
  ### Sorting
298
333
 
@@ -411,6 +446,17 @@ class UsersController < ApplicationController
411
446
  ...
412
447
  ```
413
448
 
449
+ By default, the value can not update to a value other than the value specified in the scope( or parameter). This behavior can change with `changeable` option.
450
+
451
+ ```rb
452
+ # app/controllers/users_controller.rb
453
+ class UsersController < ApplicationController
454
+ include DynamicScaffold::Controller
455
+ dynamic_scaffold User do |c|
456
+ c.scope([:role], changeable: true)
457
+ ...
458
+ ```
459
+
414
460
  #### Limit count
415
461
 
416
462
  You can specify the maximum count of registrations.
@@ -132,4 +132,36 @@
132
132
  // Fixed a problem that font-awesome icon and text link do not match in height.
133
133
  .page-link{
134
134
  line-height: 1.6;
135
+ }
136
+
137
+
138
+ .ds-globalize-group{
139
+ margin-bottom: 7px;
140
+ display: flex;
141
+ .ds-globalize-lang{
142
+ display: flex;
143
+ font-size: 12px;
144
+ color: #495057;
145
+ text-align: center;
146
+ white-space: nowrap;
147
+ background-color: #e9ecef;
148
+ border: 1px solid #ced4da;
149
+ border-radius: .25rem;
150
+ border-top-right-radius: 0;
151
+ border-bottom-right-radius: 0;
152
+ border-right: none;
153
+ justify-content: center;
154
+ align-items: center;
155
+ }
156
+
157
+ &.has-error{
158
+ .ds-globalize-lang{
159
+ border-color: #a94442;
160
+ }
161
+ }
162
+
163
+ .form-control{
164
+ border-top-left-radius: 0;
165
+ border-bottom-left-radius: 0;
166
+ }
135
167
  }
@@ -0,0 +1,14 @@
1
+ module DynamicScaffoldHelper
2
+ def render_form_errors(errors)
3
+ return '' if errors.blank?
4
+ tag.ul(class: 'list-unstyled ds-error-message') do
5
+ errors.each do |message|
6
+ concat tag.li("#{dynamic_scaffold_icon :error} #{message}".html_safe) # rubocop:disable Rails/OutputSafety
7
+ end
8
+ end
9
+ end
10
+
11
+ def dynamic_scaffold_icon(name)
12
+ instance_exec name, &::Rails.application.config.dynamic_scaffold.icons
13
+ end
14
+ end
@@ -56,6 +56,19 @@
56
56
  <%end%>
57
57
  <%= form.hidden_field "#{elem.name}_cache" %>
58
58
  </div>
59
+ <% elsif elem.type? :globalize_fields %>
60
+ <% elem.locales.each do |locale, name| %>
61
+ <%- locale_errors = elem.locale_errors(locale, @record) -%>
62
+ <%= form.globalize_fields_for(locale) do |gform|%>
63
+ <div class="<%= class_names('ds-globalize-group', 'has-error': locale_errors.present?) %>">
64
+ <%= tag.span(elem.lang_attributes('ds-globalize-lang')) do%>
65
+ <%= name %>
66
+ <%end%>
67
+ <%= elem.render(self, gform, class_names('form-control', {'is-invalid': locale_errors.present?})) %>
68
+ </div>
69
+ <%= render_form_errors(locale_errors) -%>
70
+ <%end%>
71
+ <% end %>
59
72
  <% else %>
60
73
  <%= elem.render(self, form, class_names('form-control', {'is-invalid': errors.present?})) %>
61
74
  <% end %>
@@ -63,13 +76,7 @@
63
76
  <%= self.instance_exec(@record, &block) %>
64
77
  <%-end-%>
65
78
  </div>
66
- <%- if errors.present? -%>
67
- <ul class="list-unstyled ds-error-message">
68
- <% errors.each do |err|%>
69
- <li><%= dynamic_scaffold_icon :error %> <%= err %></li>
70
- <%end%>
71
- </ul>
72
- <%- end -%>
79
+ <%= render_form_errors(errors) -%>
73
80
  <%if elem.notes?%>
74
81
  <div class="form-text text-muted"><%= elem.render_notes(form.object, self) %></div>
75
82
  <%end%>
@@ -119,7 +119,16 @@ module DynamicScaffold
119
119
  end
120
120
 
121
121
  class Config
122
- attr_reader :model, :form, :list, :title, :controller, :lock_before_count, :max_count_options
122
+ attr_reader(
123
+ :model,
124
+ :form,
125
+ :list,
126
+ :title,
127
+ :controller,
128
+ :lock_before_count,
129
+ :max_count_options,
130
+ :scope_options
131
+ )
123
132
  def initialize(model, controller)
124
133
  @model = model
125
134
  @controller = controller
@@ -139,8 +148,11 @@ module DynamicScaffold
139
148
  end
140
149
  end
141
150
 
142
- def scope(scopes = nil)
143
- @scope = scopes unless scopes.nil?
151
+ def scope(*args)
152
+ if args.present?
153
+ @scope_options = args.extract_options!
154
+ @scope = args[0]
155
+ end
144
156
  @scope
145
157
  end
146
158
 
@@ -274,40 +286,8 @@ module DynamicScaffold
274
286
  end
275
287
  end
276
288
 
277
- def item(type, *args, &block) # rubocop:disable Metrics/MethodLength
278
- case type
279
- when
280
- :check_box,
281
- :radio_button,
282
- :text_area,
283
- :text_field,
284
- :password_field,
285
- :hidden_field,
286
- :file_field,
287
- :color_field,
288
- :number_field,
289
- :telephone_field then
290
- item = Form::Item::SingleOption.new(@config, type, *args)
291
- when
292
- :time_select,
293
- :date_select,
294
- :datetime_select,
295
- :collection_select,
296
- :grouped_collection_select then
297
- item = Form::Item::TwoOptions.new(@config, type, *args)
298
- when
299
- :collection_check_boxes,
300
- :collection_radio_buttons then
301
- item = Form::Item::TwoOptionsWithBlock.new(@config, type, *args)
302
- when
303
- :block then
304
- item = Form::Item::Block.new(@config, type, *args, block)
305
- when
306
- :carrierwave_image then
307
- item = Form::Item::CarrierWaveImage.new(@config, type, *args)
308
- else
309
- raise DynamicScaffold::Error::InvalidParameter, "Unknown form item type #{type}"
310
- end
289
+ def item(type, *args, &block)
290
+ item = Form::Item::Base.create(@config, type, *args, &block)
311
291
  @items << item
312
292
  item
313
293
  end
@@ -4,7 +4,8 @@ module DynamicScaffold
4
4
  include ControllerUtilities
5
5
 
6
6
  included do
7
- helper_method :dynamic_scaffold_path, :dynamic_scaffold_icon, :dynamic_scaffold, :primary_key_value, :request_queries
7
+ helper_method :dynamic_scaffold_path, :dynamic_scaffold, :request_queries
8
+ helper DynamicScaffoldHelper
8
9
  attr_reader :dynamic_scaffold
9
10
  before_action lambda {
10
11
  @dynamic_scaffold = Config.new(self.class.dynamic_scaffold_model, self)
@@ -42,10 +42,14 @@ module DynamicScaffold
42
42
  # Get paramters for update record.
43
43
  def update_values # rubocop:disable Metrics/AbcSize
44
44
  # set the parameters of carrierwave_image at the end for validates.
45
- permitting = dynamic_scaffold.form.items.map {|f| f.strong_parameter unless f.type?(:carrierwave_image) }.compact
45
+ permitting = []
46
+ dynamic_scaffold.form.items.reject {|i| i.type?(:carrierwave_image) }.each do |item|
47
+ item.extract_parameters(permitting)
48
+ end
46
49
  permitting.concat(dynamic_scaffold.form.permit_params)
47
- permitting.concat(dynamic_scaffold.form.items.map {|f| f.strong_parameter if f.type?(:carrierwave_image) }.compact)
48
- permitting.flatten!
50
+ dynamic_scaffold.form.items.select {|i| i.type?(:carrierwave_image) }.each do |item|
51
+ item.extract_parameters(permitting)
52
+ end
49
53
 
50
54
  values = params
51
55
  .require(dynamic_scaffold.model.name.underscore)
@@ -60,6 +64,7 @@ module DynamicScaffold
60
64
 
61
65
  # Check if there are inconsistent scopes in update parameters
62
66
  def valid_for_scope?(update_params)
67
+ return true if dynamic_scaffold.scope_options[:changeable]
63
68
  result = true
64
69
  scope_params.each do |key, value|
65
70
  if update_params.key?(key) && update_params[key] != value
@@ -110,14 +115,6 @@ module DynamicScaffold
110
115
  public_send("#{route.name}_path", options)
111
116
  end
112
117
 
113
- def dynamic_scaffold_icon(name)
114
- view_context.instance_exec name, &::Rails.application.config.dynamic_scaffold.icons
115
- end
116
-
117
- def primary_key_value(record)
118
- [*record.class.primary_key].each_with_object({}) {|col, res| res[col] = record[col] }
119
- end
120
-
121
118
  def bind_sorter_value(record)
122
119
  attr = dynamic_scaffold.list.sorter_attribute
123
120
  value = dynamic_scaffold.model.maximum(attr)
@@ -1,7 +1,52 @@
1
1
  module DynamicScaffold
2
2
  module Form
3
3
  module Item
4
- class Base
4
+ class Base # rubocop:disable Metrics/ClassLength
5
+ ITEM_TYPES = {
6
+ check_box: Form::Item::SingleOption,
7
+ radio_button: Form::Item::SingleOption,
8
+ text_area: Form::Item::SingleOption,
9
+ text_field: Form::Item::SingleOption,
10
+ password_field: Form::Item::SingleOption,
11
+ hidden_field: Form::Item::SingleOption,
12
+ file_field: Form::Item::SingleOption,
13
+ color_field: Form::Item::SingleOption,
14
+ number_field: Form::Item::SingleOption,
15
+ telephone_field: Form::Item::SingleOption,
16
+
17
+ time_select: Form::Item::TwoOptions,
18
+ date_select: Form::Item::TwoOptions,
19
+ datetime_select: Form::Item::TwoOptions,
20
+ collection_select: Form::Item::TwoOptions,
21
+ grouped_collection_select: Form::Item::TwoOptions,
22
+
23
+ collection_check_boxes: Form::Item::TwoOptionsWithBlock,
24
+ collection_radio_buttons: Form::Item::TwoOptionsWithBlock,
25
+
26
+ block: Form::Item::Block,
27
+
28
+ carrierwave_image: Form::Item::CarrierWaveImage,
29
+
30
+ globalize_fields: Form::Item::GlobalizeFields
31
+ }.freeze
32
+
33
+ class << self
34
+ def create(config, type, *args, &block)
35
+ if ITEM_TYPES[type].nil?
36
+ raise(
37
+ DynamicScaffold::Error::InvalidParameter,
38
+ "Unknown form item type #{type}. supported: #{ITEM_TYPES.keys.join(', ')}"
39
+ )
40
+ end
41
+
42
+ if ITEM_TYPES[type] == Form::Item::Block
43
+ ITEM_TYPES[type].new(config, type, *args, block)
44
+ else
45
+ ITEM_TYPES[type].new(config, type, *args)
46
+ end
47
+ end
48
+ end
49
+
5
50
  attr_reader :name
6
51
  def initialize(config, type, name, html_attributes = {})
7
52
  @config = config
@@ -54,9 +99,12 @@ module DynamicScaffold
54
99
  end
55
100
  end
56
101
 
57
- def strong_parameter
58
- return { @name => [] } if @multiple
59
- @name
102
+ def extract_parameters(permitting)
103
+ if @multiple
104
+ permitting << { @name => [] }
105
+ else
106
+ permitting << @name
107
+ end
60
108
  end
61
109
 
62
110
  def if(&block)
@@ -30,13 +30,11 @@ module DynamicScaffold
30
30
  yield(html_attributes)
31
31
  end
32
32
 
33
- def strong_parameter
34
- params = []
33
+ def extract_parameters(permitting)
35
34
  # If you do not permit before the image body you can not use cropper value in uploader.
36
- params << "cropper_#{@name}" unless cropper.nil?
37
- params << "remove_#{@name}" if @options[:removable]
38
- params.concat(["#{@name}_cache", @name])
39
- params
35
+ permitting << "cropper_#{@name}" unless cropper.nil?
36
+ permitting << "remove_#{@name}" if @options[:removable]
37
+ permitting.concat(["#{@name}_cache", @name])
40
38
  end
41
39
  end
42
40
  end
@@ -0,0 +1,40 @@
1
+ module DynamicScaffold
2
+ module Form
3
+ module Item
4
+ class GlobalizeFields < Base
5
+ attr_reader :locales
6
+ delegate :proxy_field, :notes?, :render_notes, :render, to: :@item
7
+
8
+ def initialize(config, type, locales, options = {})
9
+ super(config, type, :translations_attributes, options)
10
+ @locales = locales
11
+ end
12
+
13
+ def for(type, *args, &block)
14
+ @item = Form::Item::Base.create(@config, type, *args, &block)
15
+ end
16
+
17
+ def strong_parameter
18
+ { translations_attributes: [:id, :locale, @item.name] }
19
+ end
20
+
21
+ def extract_parameters(permitting)
22
+ trans = permitting.find {|item| item.is_a?(Hash) && item.key?(:translations_attributes) }
23
+ if trans.nil?
24
+ permitting << { translations_attributes: [:id, :locale, @item.name] }
25
+ else
26
+ trans[:translations_attributes] << @item.name
27
+ end
28
+ end
29
+
30
+ def lang_attributes(classnames = nil)
31
+ build_html_attributes(classnames)
32
+ end
33
+
34
+ def locale_errors(locale, record)
35
+ record.errors.full_messages_for("#{@item.proxy_field.name}_#{locale}")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,64 @@
1
+ module ActionView
2
+ module Helpers
3
+ class FormBuilder
4
+ #
5
+ # Helper that renders translations fields
6
+ # on a per-locale basis, so you can use them separately
7
+ # in the same form and still saving them all at once
8
+ # in the same request.
9
+ #
10
+ # Use it like this:
11
+ #
12
+ # <h1>Editing post</h1>
13
+ #
14
+ # <% form_for(@post) do |f| %>
15
+ # <%= f.error_messages %>
16
+ #
17
+ # <h2>English (default locale)</h2>
18
+ # <p><%= f.text_field :title %></p>
19
+ # <p><%= f.text_field :teaser %></p>
20
+ # <p><%= f.text_field :body %></p>
21
+ #
22
+ # <hr/>
23
+ #
24
+ # <h2>Spanish translation</h2>
25
+ # <% f.globalize_fields_for :es do |g| %>
26
+ # <p><%= g.text_field :title %></p>
27
+ # <p><%= g.text_field :teaser %></p>
28
+ # <p><%= g.text_field :body %></p>
29
+ # <% end %>
30
+ #
31
+ # <hr/>
32
+ #
33
+ # <h2>French translation</h2>
34
+ # <% f.globalize_fields_for :fr do |g| %>
35
+ # <p><%= g.text_field :title %></p>
36
+ # <p><%= g.text_field :teaser %></p>
37
+ # <p><%= g.text_field :body %></p>
38
+ # <% end %>
39
+ #
40
+ # <% end %>
41
+ #
42
+ def globalize_fields_for(locale, *args, &proc)
43
+ raise ArgumentError, 'Missing block' unless block_given?
44
+ @locales ||= []
45
+
46
+ first = false
47
+ unless @locales.include?(locale)
48
+ @locales << locale
49
+ first = true
50
+ end
51
+ object_name = "#{@object_name}[translations_attributes][#{@locales.index(locale) + 1}]"
52
+ object = @object.translations.find_by locale: locale.to_s
53
+
54
+ # The following tags are added only once for the first time.
55
+ if first
56
+ @template.concat @template.hidden_field_tag("#{object_name}[id]", object ? object.id : '')
57
+ @template.concat @template.hidden_field_tag("#{object_name}[locale]", locale)
58
+ end
59
+
60
+ @template.fields_for(object_name, object, *args, &proc)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module DynamicScaffold
2
- VERSION = '0.8.5'.freeze
2
+ VERSION = '0.9.0'.freeze
3
3
  end
@@ -4,6 +4,7 @@ require 'dynamic_scaffold/routes'
4
4
  require 'dynamic_scaffold/controller_utilities'
5
5
  require 'dynamic_scaffold/controller'
6
6
  require 'dynamic_scaffold/config'
7
+ require 'dynamic_scaffold/form_builder'
7
8
 
8
9
  module DynamicScaffold
9
10
  module Error
@@ -25,6 +26,7 @@ module DynamicScaffold
25
26
  autoload :SingleOption, 'dynamic_scaffold/form/item/single_option'
26
27
  autoload :TwoOptionsWithBlock, 'dynamic_scaffold/form/item/two_options_with_block'
27
28
  autoload :TwoOptions, 'dynamic_scaffold/form/item/two_options'
29
+ autoload :GlobalizeFields, 'dynamic_scaffold/form/item/globalize_fields'
28
30
  end
29
31
  end
30
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamic_scaffold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masamoto Miyata
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-31 00:00:00.000000000 Z
11
+ date: 2018-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: classnames-rails-view
@@ -233,6 +233,7 @@ files:
233
233
  - app/assets/stylesheets/dynamic_scaffold/bootstrap4.scss
234
234
  - app/assets/stylesheets/dynamic_scaffold/common.scss
235
235
  - app/assets/stylesheets/dynamic_scaffold/resplist.scss
236
+ - app/helpers/dynamic_scaffold_helper.rb
236
237
  - app/views/dynamic_scaffold/bootstrap/_edit.html.erb
237
238
  - app/views/dynamic_scaffold/bootstrap/_form.html.erb
238
239
  - app/views/dynamic_scaffold/bootstrap/_list.html.erb
@@ -261,9 +262,11 @@ files:
261
262
  - lib/dynamic_scaffold/form/item/base.rb
262
263
  - lib/dynamic_scaffold/form/item/block.rb
263
264
  - lib/dynamic_scaffold/form/item/carrier_wave_image.rb
265
+ - lib/dynamic_scaffold/form/item/globalize_fields.rb
264
266
  - lib/dynamic_scaffold/form/item/single_option.rb
265
267
  - lib/dynamic_scaffold/form/item/two_options.rb
266
268
  - lib/dynamic_scaffold/form/item/two_options_with_block.rb
269
+ - lib/dynamic_scaffold/form_builder.rb
267
270
  - lib/dynamic_scaffold/icons/fontawesome.rb
268
271
  - lib/dynamic_scaffold/list/item.rb
269
272
  - lib/dynamic_scaffold/routes.rb