dynamic_scaffold 1.7.1 → 1.10.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: a42e42644e59b8b8f43dfe73eed5089f76f471c20bbd788c44c2e3eb0ba68ea3
4
- data.tar.gz: aaa19ee4e6ff49e27e12c1383f7ec3233ec3dcb436eca830b52c4fe5b2901d85
3
+ metadata.gz: d2878d75af1c0e57b392261a63012a7e8adaf8b527cc6da8bb7c8ea5f84011a5
4
+ data.tar.gz: 5a0037e29736c6863901d7f7fdbec3aaeefd0a1ebb746d21f49c3356838cfcf5
5
5
  SHA512:
6
- metadata.gz: aa010c42fbdbf64be8d31c8eb2323ba27219dd94639ea8d10de646b9b028deef6400b7aba98463e62b2bb98dfe01e9aa2f6a4dcb84ead17e65555af1e79dfd24
7
- data.tar.gz: b06d1e642763f3b399a098316bb4de3bc8af90bb3765d3fb22bf13bc525c57115c4a6cbafe25d4b4b9ae941d8ff3bdffeebacf975e2bb977948c0978e9ae2745
6
+ metadata.gz: 9ef5af49b21cd93f46e1e13138eff64823fe3e5379882bdf0910e8082ecba8d7f9b65dd8c8b6cde8c22fb0fbb7fe5f92ffc1c31e61bfd7fd18a22fbdd8756022
7
+ data.tar.gz: bb3b7662d02ebda9658ada08ce216e63ac24f4c63d2434757cc924c6e56ae8ab4b3156809b062824b7251d14037791fa00189eeace66498f53117b7fb8d8b44c
data/README.md CHANGED
@@ -157,6 +157,34 @@ You can customize the list through the `DynamicScaffold::Config#list` property.
157
157
  class ShopController < ApplicationController
158
158
  include DynamicScaffold::Controller
159
159
  dynamic_scaffold Shop do |config|
160
+ # Add button and new action to disabled, You can still post to create action.
161
+ config.list.add_button = false
162
+ # or
163
+ config.list.add_button do
164
+ # This block is called in view scope
165
+ false if params[:foo] == 1
166
+ end
167
+
168
+ # Edit button and edit action to disabled, You can still post to update action.
169
+ config.list.edit_buttons = false
170
+ # or
171
+ config.list.edit_buttons do |record|
172
+ # This block is called in view scope
173
+ # You can disable only specific record's button.
174
+ false if record.id != 1
175
+ end
176
+
177
+ # Destroy button to disabled, You can still post to destroy action.
178
+ config.list.destroy_buttons = false
179
+ # or
180
+ config.list.destroy_buttons do |record|
181
+ # This block is called in view scope
182
+ # You can disable only specific record's button.
183
+ false if record.id != 1
184
+ end
185
+
186
+
187
+
160
188
  # If you want filtering that can not be handled by `config.scope`, you can use the filter method.
161
189
  # Please note that returning nil will be ignored.
162
190
  config.list.filter do |query|
@@ -253,6 +281,9 @@ class ShopController < ApplicationController
253
281
  config.form.item(:collection_check_boxes, :state_ids, State.all, :id, :name)
254
282
  config.form.item(:collection_radio_buttons, :status, Shop.statuses.map{|k, _v| [k, k.titleize]}, :first, :last)
255
283
 
284
+ # If you want to use parameters to get list, Pass Proc or Lambda to argument. It will be called in view scope.
285
+ config.form.item(:collection_select, :status, -> { Shop.where(area_id: params[:area_id]) }, :first, :last)
286
+
256
287
  # If you want to display more free form field, use block.
257
288
  # The block is executed in the context of view, so you can call the method of view.
258
289
  config.form.item :block, :free do |form, field|
@@ -364,6 +395,12 @@ We support [cocoon](https://github.com/nathanvda/cocoon).
364
395
  end
365
396
  ```
366
397
 
398
+ ##### json_object
399
+
400
+ You can save json object string in a column using each form items and validations.
401
+ Check this [wiki](https://github.com/gomo/dynamic_scaffold/wiki/Handling-json-object-string-column)
402
+
403
+
367
404
  #### Overwrite actions
368
405
 
369
406
  You can pass the block to super in index/create/update actions.
@@ -5,16 +5,18 @@
5
5
  <%end%>
6
6
  <input type="hidden" class="authenticity_param_name" value="<%= request_forgery_protection_token %>">
7
7
  <%= form_with method: :patch, url: dynamic_scaffold_path(:sort, request_queries(dynamic_scaffold.list.page_param_name)), local: true do%>
8
- <div class="ds-row">
9
- <%= link_to dynamic_scaffold_path(:new, request_queries), class: class_names('btn btn-outline-primary btn-primary btn-sm spec-ds-add', 'disabled': dynamic_scaffold.max_count?(@count)) do%>
10
- <%= dynamic_scaffold_icon(:add) %> <%= t('dynamic_scaffold.button.add') %>
11
- <%- unless dynamic_scaffold.max_count.nil? -%>
12
- &nbsp;<span class="badge badge-light">
13
- <%= @count %>&nbsp;/&nbsp;<%= dynamic_scaffold.max_count%>
14
- </span>
15
- <% end %>
16
- <%end%>
17
- </div>
8
+ <%- if dynamic_scaffold.list.add_button -%>
9
+ <div class="ds-row">
10
+ <%= link_to dynamic_scaffold_path(:new, request_queries), class: class_names('btn btn-outline-primary btn-primary btn-sm spec-ds-add', 'disabled': dynamic_scaffold.max_count?(@count)) do%>
11
+ <%= dynamic_scaffold_icon(:add) %> <%= t('dynamic_scaffold.button.add') %>
12
+ <%- unless dynamic_scaffold.max_count.nil? -%>
13
+ &nbsp;<span class="badge badge-light">
14
+ <%= @count %>&nbsp;/&nbsp;<%= dynamic_scaffold.max_count%>
15
+ </span>
16
+ <% end %>
17
+ <%end%>
18
+ </div>
19
+ <%- end -%>
18
20
  <%= render 'dynamic_scaffold/bootstrap/pagination' %>
19
21
  <div class="ds-row">
20
22
  <%= render 'dynamic_scaffold/bootstrap/save_order'%>
@@ -47,11 +49,13 @@
47
49
  </div>
48
50
  <div class="ds-list-footer clearfix">
49
51
  <div class="float-right pull-right">
50
- <div class="btn-group">
51
- <%= link_to dynamic_scaffold_path(:edit, request_queries.merge(id: record[record.class.primary_key])), class: 'btn btn-primary btn-outline-primary btn-sm spec-ds-edit' do %>
52
- <%= dynamic_scaffold_icon(:edit) %> <%= t('dynamic_scaffold.button.edit') %>
53
- <%end%>
54
- </div>
52
+ <%- if dynamic_scaffold.list.edit_buttons(record) -%>
53
+ <div class="btn-group">
54
+ <%= link_to dynamic_scaffold_path(:edit, request_queries.merge(id: record[record.class.primary_key])), class: 'btn btn-primary btn-outline-primary btn-sm spec-ds-edit' do %>
55
+ <%= dynamic_scaffold_icon(:edit) %> <%= t('dynamic_scaffold.button.edit') %>
56
+ <%end%>
57
+ </div>
58
+ <%- end -%>
55
59
  <% if dynamic_scaffold.list.sorter %>
56
60
  <%[*dynamic_scaffold.model.primary_key].each do |pkey|%>
57
61
  <input type="hidden" name="pkeys[][<%=pkey%>]" value="<%= record[pkey] %>">
@@ -71,15 +75,17 @@
71
75
  </button>
72
76
  </div>
73
77
  <% end %>
74
- <div class="btn-group">
75
- <button
76
- data-action="<%= dynamic_scaffold_path(:update, request_queries(dynamic_scaffold.list.page_param_name).merge(id: record[record.class.primary_key])) %>"
77
- data-confirm-message="<%= t('dynamic_scaffold.message.destroy_confirm') %>"
78
- class="btn btn-danger btn-sm js-ds-destory"
79
- >
80
- <%= dynamic_scaffold_icon(:delete) %>
81
- </button>
82
- </div>
78
+ <%- if dynamic_scaffold.list.destroy_buttons(record) -%>
79
+ <div class="btn-group">
80
+ <button
81
+ data-action="<%= dynamic_scaffold_path(:update, request_queries(dynamic_scaffold.list.page_param_name).merge(id: record[record.class.primary_key])) %>"
82
+ data-confirm-message="<%= t('dynamic_scaffold.message.destroy_confirm') %>"
83
+ class="btn btn-danger btn-sm js-ds-destory spec-ds-destroy"
84
+ >
85
+ <%= dynamic_scaffold_icon(:delete) %>
86
+ </button>
87
+ </div>
88
+ <%- end -%>
83
89
  </div>
84
90
  </div>
85
91
  </li>
@@ -68,7 +68,7 @@
68
68
  <%end%>
69
69
  <% end %>
70
70
  <% elsif elem.type? :cocoon %>
71
- <%= form.fields_for elem.name, elem.build_children(@record) do |child_form| %>
71
+ <%= form.fields_for(elem.name, elem.build_children(@record)) do |child_form| %>
72
72
  <%= render 'dynamic_scaffold/bootstrap/form/cocoon', f: child_form, items: elem.form.items, depth: depth %>
73
73
  <% end %>
74
74
  <%= link_to_add_association(
@@ -86,6 +86,12 @@
86
86
  .gsub(/ : /, '<span class="mr-2" style="display: inline-block;">:</span>')
87
87
  %>
88
88
  </div>
89
+ <% elsif elem.type?(:json_object) %>
90
+ <%= form.fields_for(elem.name, @record.public_send(elem.name)) do |child_form| %>
91
+ <%- elem.form.items.each do |child_elem|-%>
92
+ <%= render 'dynamic_scaffold/bootstrap/form/row', form: child_form, elem: child_elem, depth: depth %>
93
+ <% end %>
94
+ <% end %>
89
95
  <% else %>
90
96
  <%= elem.render(self, form, class_names('form-control', {'is-invalid': errors.present?})) %>
91
97
  <% end %>
@@ -32,8 +32,14 @@ module DynamicScaffold
32
32
  autoload :SingleOption, 'dynamic_scaffold/form/item/single_option'
33
33
  autoload :TwoOptionsWithBlock, 'dynamic_scaffold/form/item/two_options_with_block'
34
34
  autoload :TwoOptions, 'dynamic_scaffold/form/item/two_options'
35
- autoload :GlobalizeFields, 'dynamic_scaffold/form/item/globalize_fields'
36
- autoload :Cocoon, 'dynamic_scaffold/form/item/cocoon'
35
+ autoload :GlobalizeFields, 'dynamic_scaffold/form/item/globalize_fields'
36
+ autoload :Cocoon, 'dynamic_scaffold/form/item/cocoon'
37
+ autoload :JSONObject, 'dynamic_scaffold/form/item/json_object'
37
38
  end
38
39
  end
40
+
41
+ module JSONObject
42
+ autoload :Attribute, 'dynamic_scaffold/json_object/attribute'
43
+ autoload :Model, 'dynamic_scaffold/json_object/model'
44
+ end
39
45
  end
@@ -44,6 +44,8 @@ module DynamicScaffold
44
44
  end
45
45
 
46
46
  def new # rubocop:disable Metrics/AbcSize
47
+ raise ActionController::RoutingError, '`Add Button` is disabled.' unless dynamic_scaffold.list.add_button
48
+
47
49
  unless dynamic_scaffold.max_count.nil?
48
50
  count = dynamic_scaffold.list.build_sql(scope_params).count
49
51
  raise Error::InvalidOperation, 'You can not add any more.' if dynamic_scaffold.max_count?(count)
@@ -60,6 +62,8 @@ module DynamicScaffold
60
62
 
61
63
  def edit
62
64
  @record = find_record(edit_params)
65
+
66
+ raise ActionController::RoutingError, '`Edit Button` is disabled.' unless dynamic_scaffold.list.edit_buttons(@record)
63
67
  end
64
68
 
65
69
  def create
@@ -77,7 +81,7 @@ module DynamicScaffold
77
81
  end
78
82
  end
79
83
 
80
- def update # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
84
+ def update # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
81
85
  values = update_values
82
86
  @record = find_record(dynamic_scaffold.model.primary_key => params['id'])
83
87
  datetime_select_keys = []
@@ -93,6 +97,9 @@ module DynamicScaffold
93
97
  # globalize
94
98
  next [:translations_attributes, @record.translations] if k == 'translations_attributes'
95
99
 
100
+ # skip nested_attributes
101
+ next unless @record.respond_to? k
102
+
96
103
  [k, @record.public_send(k)]
97
104
  end.compact.to_h.with_indifferent_access
98
105
 
@@ -15,7 +15,8 @@ module DynamicScaffold
15
15
  end
16
16
  end
17
17
 
18
- attr_reader :name
18
+ attr_accessor :parent_item
19
+ attr_reader :name, :multiple
19
20
  def initialize(config, type, name, html_attributes = {})
20
21
  @config = config
21
22
  @name = name
@@ -32,7 +33,10 @@ module DynamicScaffold
32
33
  end
33
34
 
34
35
  def unique_name
35
- "#{@config.model.table_name}_#{name}"
36
+ results = [@config.model.table_name]
37
+ results << parent_item.name if parent_item.present?
38
+ results << name
39
+ results.join('_')
36
40
  end
37
41
 
38
42
  def notes?
@@ -180,6 +184,14 @@ module DynamicScaffold
180
184
  options[:class] = classnames_list.join(' ') unless classnames_list.empty?
181
185
  options
182
186
  end
187
+
188
+ def build_args(view, args)
189
+ args.map do |arg|
190
+ next arg unless arg.is_a? Proc
191
+
192
+ view.instance_exec(&arg)
193
+ end
194
+ end
183
195
  end
184
196
  end
185
197
  end
@@ -2,8 +2,8 @@ module DynamicScaffold
2
2
  module Form
3
3
  module Item
4
4
  class Block < Base
5
- def initialize(config, type, name, &block)
6
- super(config, type, name, {})
5
+ def initialize(config, type, name, options = {}, &block)
6
+ super(config, type, name, options)
7
7
  @block = block
8
8
  end
9
9
 
@@ -7,6 +7,7 @@ module DynamicScaffold
7
7
  super
8
8
  @options = options
9
9
  @form = FormBuilder.new(config)
10
+ @form.parent_item = self
10
11
  yield(@form)
11
12
  end
12
13
 
@@ -0,0 +1,32 @@
1
+ module DynamicScaffold
2
+ module Form
3
+ module Item
4
+ class JSONObject < Base
5
+ attr_reader :form
6
+ def initialize(config, type, name, options = {})
7
+ super
8
+ @options = options
9
+ @form = FormBuilder.new(config)
10
+ @form.parent_item = self
11
+ yield(@form)
12
+ end
13
+
14
+ # the lable is always empty.
15
+ def render_label(_view, _depth)
16
+ ''
17
+ end
18
+
19
+ def extract_parameters(permitting)
20
+ hash = permitting.find {|e| e.is_a?(Hash) && e.key?(name) }
21
+ if hash.nil?
22
+ hash = {}
23
+ hash[name] = form.items.map(&:name)
24
+ permitting << hash
25
+ else
26
+ hash[name].concat(form.items.map(&:name))
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -9,11 +9,11 @@ module DynamicScaffold
9
9
  super(config, type, name, html_attributes)
10
10
  end
11
11
 
12
- def render(_view, form, classnames = nil)
12
+ def render(view, form, classnames = nil)
13
13
  html_attributes = build_html_attributes(classnames)
14
14
  # Retain the value of the password field on error.
15
15
  html_attributes[:value] = form.object.public_send(@name) if @type == :password_field
16
- form.public_send(@type, @name, *@args, html_attributes)
16
+ form.public_send(@type, @name, *build_args(view, @args), html_attributes)
17
17
  end
18
18
  end
19
19
  end
@@ -18,9 +18,9 @@ module DynamicScaffold
18
18
  super(config, type, name, html_attributes)
19
19
  end
20
20
 
21
- def render(_view, form, classnames = nil)
21
+ def render(view, form, classnames = nil)
22
22
  html_attributes = build_html_attributes(classnames)
23
- form.public_send(@type, @name, *@args, @options, html_attributes)
23
+ form.public_send(@type, @name, *build_args(view, @args), @options, html_attributes)
24
24
  end
25
25
  end
26
26
  end
@@ -2,11 +2,11 @@ module DynamicScaffold
2
2
  module Form
3
3
  module Item
4
4
  class TwoOptionsWithBlock < TwoOptions
5
- def render(_view, form, classnames = nil)
5
+ def render(view, form, classnames = nil)
6
6
  form.public_send(
7
7
  @type,
8
8
  @name,
9
- *@args,
9
+ *build_args(view, @args),
10
10
  @options,
11
11
  build_html_attributes(classnames)
12
12
  ) do |builder|
@@ -30,7 +30,9 @@ module DynamicScaffold
30
30
 
31
31
  globalize_fields: Form::Item::GlobalizeFields,
32
32
 
33
- cocoon: Form::Item::Cocoon
33
+ cocoon: Form::Item::Cocoon,
34
+
35
+ json_object: Form::Item::JSONObject
34
36
  }.freeze
35
37
  end
36
38
  end
@@ -1,5 +1,7 @@
1
1
  module DynamicScaffold
2
2
  class FormBuilder
3
+ attr_accessor :parent_item
4
+
3
5
  def initialize(config)
4
6
  @config = config
5
7
  @items = []
@@ -11,7 +13,9 @@ module DynamicScaffold
11
13
  @config.model.column_names.each do |column|
12
14
  type = :text_field
13
15
  type = :hidden_field if @config.scope && @config.scope.include?(column.to_sym)
14
- @items << Form::Item::SingleOption.new(@config, type, column)
16
+ item = Form::Item::SingleOption.new(@config, type, column)
17
+ item.parent_item = parent_item
18
+ @items << item
15
19
  end
16
20
  end
17
21
  @items
@@ -28,6 +32,7 @@ module DynamicScaffold
28
32
 
29
33
  def item(type, *args, &block)
30
34
  item = Form::Item::Base.create(@config, type, *args, &block)
35
+ item.parent_item = parent_item
31
36
  @items << item
32
37
  item
33
38
  end
@@ -0,0 +1,24 @@
1
+ module DynamicScaffold
2
+ module JSONObject
3
+ module Attribute
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ @json_object_attribute_names ||= []
8
+
9
+ define_method :valid? do |context = nil|
10
+ result = super(context)
11
+ json_object_attribute_names = self.class.instance_variable_get(:@json_object_attribute_names)
12
+ json_object_attribute_names.all? {|method| public_send(method).valid?(context) } && result
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def json_object_attributte(attribute_name, model)
18
+ @json_object_attribute_names << attribute_name
19
+ serialize attribute_name, model
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module DynamicScaffold
2
+ module JSONObject
3
+ module Model
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def dump(obj)
8
+ obj = obj.attributes if obj.is_a? ActiveModel::Attributes
9
+ obj.to_json if obj
10
+ end
11
+
12
+ def load(source)
13
+ new(source ? JSON.parse(source) : {})
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,7 @@
1
1
  module DynamicScaffold
2
2
  class ListBuilder
3
+ attr_writer :add_button, :edit_buttons, :destroy_buttons
4
+
3
5
  def initialize(config)
4
6
  @config = config
5
7
  @items = []
@@ -8,6 +10,9 @@ module DynamicScaffold
8
10
  @title = nil
9
11
  @filter = nil
10
12
  @row_class_block = nil
13
+ @add_button = true
14
+ @edit_buttons = true
15
+ @destroy_buttons = true
11
16
  end
12
17
 
13
18
  def pagination(options = nil)
@@ -97,5 +102,35 @@ module DynamicScaffold
97
102
  @config.controller.view_context.instance_exec(record, &@row_class_block)
98
103
  end
99
104
  end
105
+
106
+ def add_button(&block)
107
+ if block_given?
108
+ @add_button_block = block
109
+ elsif @add_button_block
110
+ @config.controller.view_context.instance_exec(&@add_button_block)
111
+ else
112
+ @add_button
113
+ end
114
+ end
115
+
116
+ def edit_buttons(record = nil, &block)
117
+ if block_given?
118
+ @edit_buttons_block = block
119
+ elsif record.present? && @edit_buttons_block
120
+ @config.controller.view_context.instance_exec(record, &@edit_buttons_block)
121
+ else
122
+ @edit_buttons
123
+ end
124
+ end
125
+
126
+ def destroy_buttons(record = nil, &block)
127
+ if block_given?
128
+ @destroy_buttons_block = block
129
+ elsif record.present? && @destroy_buttons_block
130
+ @config.controller.view_context.instance_exec(record, &@destroy_buttons_block)
131
+ else
132
+ @destroy_buttons
133
+ end
134
+ end
100
135
  end
101
136
  end
@@ -1,3 +1,3 @@
1
1
  module DynamicScaffold
2
- VERSION = '1.7.1'.freeze
2
+ VERSION = '1.10.0'.freeze
3
3
  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: 1.7.1
4
+ version: 1.10.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: 2021-01-30 00:00:00.000000000 Z
11
+ date: 2021-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: classnames-rails-view
@@ -295,12 +295,15 @@ files:
295
295
  - lib/dynamic_scaffold/form/item/carrier_wave_image.rb
296
296
  - lib/dynamic_scaffold/form/item/cocoon.rb
297
297
  - lib/dynamic_scaffold/form/item/globalize_fields.rb
298
+ - lib/dynamic_scaffold/form/item/json_object.rb
298
299
  - lib/dynamic_scaffold/form/item/single_option.rb
299
300
  - lib/dynamic_scaffold/form/item/two_options.rb
300
301
  - lib/dynamic_scaffold/form/item/two_options_with_block.rb
301
302
  - lib/dynamic_scaffold/form/item/type.rb
302
303
  - lib/dynamic_scaffold/form_builder.rb
303
304
  - lib/dynamic_scaffold/icons/fontawesome.rb
305
+ - lib/dynamic_scaffold/json_object/attribute.rb
306
+ - lib/dynamic_scaffold/json_object/model.rb
304
307
  - lib/dynamic_scaffold/list/item.rb
305
308
  - lib/dynamic_scaffold/list/pagination.rb
306
309
  - lib/dynamic_scaffold/list_builder.rb