active_scaffold 3.6.0.pre → 3.6.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{CHANGELOG → CHANGELOG.rdoc} +39 -0
- data/app/assets/javascripts/active_scaffold.js.erb +0 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +35 -4
- data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
- data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
- data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
- data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
- data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
- data/config/locales/de.yml +2 -1
- data/config/locales/en.yml +1 -0
- data/config/locales/es.yml +1 -0
- data/config/locales/fr.yml +2 -1
- data/config/locales/hu.yml +1 -0
- data/config/locales/ja.yml +1 -0
- data/config/locales/ru.yml +1 -0
- data/lib/active_scaffold.rb +8 -3
- data/lib/active_scaffold/actions/common_search.rb +11 -8
- data/lib/active_scaffold/actions/core.rb +79 -51
- data/lib/active_scaffold/actions/create.rb +27 -27
- data/lib/active_scaffold/actions/delete.rb +1 -1
- data/lib/active_scaffold/actions/field_search.rb +52 -42
- data/lib/active_scaffold/actions/list.rb +106 -23
- data/lib/active_scaffold/actions/nested.rb +59 -42
- data/lib/active_scaffold/actions/show.rb +3 -3
- data/lib/active_scaffold/actions/subform.rb +9 -16
- data/lib/active_scaffold/actions/update.rb +95 -77
- data/lib/active_scaffold/attribute_params.rb +93 -68
- data/lib/active_scaffold/bridges/active_storage.rb +6 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
- data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
- data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
- data/lib/active_scaffold/bridges/bitfields.rb +1 -0
- data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +6 -0
- data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
- data/lib/active_scaffold/bridges/date_picker/helper.rb +46 -41
- data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +2 -2
- data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
- data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +3 -1
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
- data/lib/active_scaffold/bridges/record_select/helpers.rb +3 -7
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +19 -18
- data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
- data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +20 -3
- data/lib/active_scaffold/config/base.rb +58 -34
- data/lib/active_scaffold/config/core.rb +31 -12
- data/lib/active_scaffold/config/delete.rb +12 -1
- data/lib/active_scaffold/config/list.rb +17 -7
- data/lib/active_scaffold/config/mark.rb +1 -1
- data/lib/active_scaffold/configurable.rb +5 -3
- data/lib/active_scaffold/constraints.rb +21 -19
- data/lib/active_scaffold/core.rb +35 -26
- data/lib/active_scaffold/data_structures/action_columns.rb +1 -1
- data/lib/active_scaffold/data_structures/action_link.rb +34 -16
- data/lib/active_scaffold/data_structures/action_links.rb +9 -11
- data/lib/active_scaffold/data_structures/association/abstract.rb +35 -13
- data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
- data/lib/active_scaffold/data_structures/association/active_record.rb +5 -1
- data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
- data/lib/active_scaffold/data_structures/column.rb +49 -58
- data/lib/active_scaffold/data_structures/columns.rb +3 -2
- data/lib/active_scaffold/data_structures/nested_info.rb +20 -18
- data/lib/active_scaffold/data_structures/sorting.rb +5 -0
- data/lib/active_scaffold/delayed_setup.rb +16 -6
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +1 -1
- data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
- data/lib/active_scaffold/extensions/cow_proxy.rb +50 -2
- data/lib/active_scaffold/extensions/localize.rb +3 -1
- data/lib/active_scaffold/extensions/routing_mapper.rb +2 -2
- data/lib/active_scaffold/extensions/to_label.rb +3 -2
- data/lib/active_scaffold/finder.rb +81 -46
- data/lib/active_scaffold/helpers/action_link_helpers.rb +47 -21
- data/lib/active_scaffold/helpers/association_helpers.rb +13 -11
- data/lib/active_scaffold/helpers/controller_helpers.rb +14 -11
- data/lib/active_scaffold/helpers/form_column_helpers.rb +133 -99
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
- data/lib/active_scaffold/helpers/id_helpers.rb +4 -0
- data/lib/active_scaffold/helpers/list_column_helpers.rb +76 -49
- data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
- data/lib/active_scaffold/helpers/search_column_helpers.rb +25 -30
- data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
- data/lib/active_scaffold/helpers/view_helpers.rb +31 -22
- data/lib/active_scaffold/orm_checks.rb +2 -2
- data/lib/active_scaffold/paginator.rb +1 -3
- data/lib/active_scaffold/registry.rb +11 -0
- data/lib/active_scaffold/responds_to_parent.rb +6 -5
- data/lib/active_scaffold/tableless.rb +6 -8
- data/lib/active_scaffold/version.rb +1 -1
- data/shoulda_macros/macros.rb +3 -1
- data/test/bridges/paperclip_test.rb +1 -1
- data/test/company.rb +2 -2
- data/test/data_structures/action_columns_test.rb +2 -2
- data/test/data_structures/column_test.rb +3 -6
- data/test/data_structures/columns_test.rb +2 -2
- data/test/extensions/active_record_test.rb +4 -4
- data/test/extensions/routing_mapper_test.rb +2 -2
- data/test/helpers/list_column_helpers_test.rb +3 -1
- data/test/misc/active_record_permissions_test.rb +2 -2
- data/test/misc/attribute_params_test.rb +4 -0
- data/test/misc/configurable_test.rb +10 -10
- data/test/misc/convert_numbers_format_test.rb +4 -0
- data/test/mock_app/app/assets/config/manifest.js +0 -0
- data/test/mock_app/app/controllers/cars_controller.rb +1 -0
- data/test/mock_app/app/controllers/people_controller.rb +3 -1
- data/test/mock_app/config/application.rb +1 -0
- data/test/mock_app/config/routes.rb +4 -1
- data/test/mock_app/db/schema.rb +2 -0
- data/test/performance/list_cars_performance_test.rb +34 -0
- data/test/performance/list_people_performance_test.rb +31 -0
- data/test/performance_test_help.rb +3 -0
- data/test/test_helper.rb +2 -1
- metadata +22 -12
- data/app/assets/javascripts/prototype/rico_corner.js +0 -370
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -5
@@ -16,11 +16,8 @@ module ActiveScaffold
|
|
16
16
|
def association_options_find(association, conditions = nil, klass = nil, record = nil)
|
17
17
|
if klass.nil? && association.polymorphic?
|
18
18
|
class_name = record.send(association.foreign_type) if association.belongs_to?
|
19
|
-
if class_name.
|
20
|
-
|
21
|
-
else
|
22
|
-
return []
|
23
|
-
end
|
19
|
+
return [] if class_name.blank?
|
20
|
+
klass = class_name.constantize
|
24
21
|
cache = !block_given?
|
25
22
|
else
|
26
23
|
cache = !block_given? && klass.nil?
|
@@ -37,7 +34,9 @@ module ActiveScaffold
|
|
37
34
|
relation = relation.includes(include_assoc[association.name]) if include_assoc
|
38
35
|
end
|
39
36
|
if column&.sort && column.sort&.dig(:sql)
|
40
|
-
|
37
|
+
# with threasafe enabled, column.sort[:sql] returns proxied strings and
|
38
|
+
# regexp capture won't work, which rails uses internally, so to_s is needed
|
39
|
+
relation = relation.order(Array(column.sort[:sql]).map(&:to_s))
|
41
40
|
end
|
42
41
|
relation = yield(relation) if block_given?
|
43
42
|
relation.to_a
|
@@ -45,7 +44,11 @@ module ActiveScaffold
|
|
45
44
|
end
|
46
45
|
|
47
46
|
def column_for_association(association, record)
|
48
|
-
active_scaffold_config_for(record.class).columns[association.name]
|
47
|
+
active_scaffold_config_for(record.class).columns[association.name]
|
48
|
+
rescue StandardError => e
|
49
|
+
message = "Error on config for #{record.class.name}:"
|
50
|
+
Rails.logger.warn "#{message}\n#{e.message}\n#{e.backtrace.join("\n")}"
|
51
|
+
nil
|
49
52
|
end
|
50
53
|
|
51
54
|
def association_klass_scoped(association, klass, record)
|
@@ -86,10 +89,9 @@ module ActiveScaffold
|
|
86
89
|
# Check association.name to specialize the conditions per-column.
|
87
90
|
def options_for_association_conditions(association, record = nil)
|
88
91
|
return nil if association.through?
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
end
|
92
|
+
return nil unless association.has_one? || association.has_many?
|
93
|
+
# Find only orphaned objects
|
94
|
+
{association.foreign_key => nil}
|
93
95
|
end
|
94
96
|
|
95
97
|
def record_select_params_for_add_existing(association, edit_associated_url_options, record)
|
@@ -2,15 +2,14 @@ module ActiveScaffold
|
|
2
2
|
module Helpers
|
3
3
|
module ControllerHelpers
|
4
4
|
def self.included(controller)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
5
|
+
return unless controller.respond_to? :helper_method
|
6
|
+
controller.class_eval do
|
7
|
+
helper_method :params_for, :conditions_from_params, :render_parent?,
|
8
|
+
:main_path_to_return, :render_parent_options,
|
9
|
+
:render_parent_action, :nested_singular_association?,
|
10
|
+
:main_form_controller, :build_associated,
|
11
|
+
:generate_temporary_id, :generated_id,
|
12
|
+
:active_scaffold_config_for
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
@@ -27,10 +26,14 @@ module ActiveScaffold
|
|
27
26
|
|
28
27
|
def generate_temporary_id(record = nil, generated_id = nil)
|
29
28
|
(generated_id || (Time.now.to_f * 1000).to_i.to_s).tap do |id|
|
30
|
-
|
29
|
+
cache_generated_id record, id
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
33
|
+
def cache_generated_id(record, generated_id)
|
34
|
+
(@temporary_ids ||= {})[record.class.name] = generated_id if record && generated_id
|
35
|
+
end
|
36
|
+
|
34
37
|
def generated_id(record)
|
35
38
|
@temporary_ids[record.class.name] if record && @temporary_ids
|
36
39
|
end
|
@@ -101,7 +104,7 @@ module ActiveScaffold
|
|
101
104
|
else
|
102
105
|
exclude_parameters = %i[utf8 associated_id]
|
103
106
|
parameters = {}
|
104
|
-
if params[:parent_scaffold] &&
|
107
|
+
if params[:parent_scaffold] && nested_singular_association?
|
105
108
|
parameters[:controller] = params[:parent_scaffold]
|
106
109
|
exclude_parameters.concat [nested.param_name, :association, :parent_scaffold]
|
107
110
|
# parameters[:eid] = params[:parent_scaffold] # not neeeded anymore?
|
@@ -16,47 +16,43 @@ module ActiveScaffold
|
|
16
16
|
# first, check if the dev has created an override for this specific field
|
17
17
|
if (method = override_form_field(column))
|
18
18
|
send(method, record, options)
|
19
|
+
|
19
20
|
# second, check if the dev has specified a valid form_ui for this column
|
20
21
|
elsif column.form_ui && (method = override_input(column.form_ui))
|
21
22
|
send(method, column, options)
|
22
|
-
|
23
|
-
|
24
|
-
if column.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
if column.column.type == :string && options[:maxlength].blank?
|
46
|
-
options[:maxlength] = column.column.limit
|
47
|
-
options[:size] ||= options[:maxlength].to_i > 30 ? 30 : options[:maxlength]
|
48
|
-
end
|
49
|
-
options[:value] = format_number_value(record.send(column.name), column.options) if column.number?
|
50
|
-
text_field(:record, column.name, options.merge(column.options).except(:format))
|
51
|
-
end
|
23
|
+
|
24
|
+
elsif column.association
|
25
|
+
# if we get here, it's because the column has a form_ui but not one ActiveScaffold knows about.
|
26
|
+
raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'" if column.form_ui
|
27
|
+
|
28
|
+
# its an association and nothing is specified, we will assume form_ui :select
|
29
|
+
active_scaffold_input_select(column, options)
|
30
|
+
|
31
|
+
elsif column.virtual?
|
32
|
+
options[:value] = format_number_value(record.send(column.name), column.options) if column.number?
|
33
|
+
active_scaffold_input_virtual(column, options)
|
34
|
+
|
35
|
+
elsif (method = override_input(column.column.type)) # regular model attribute column
|
36
|
+
# if we (or someone else) have created a custom render option for the column type, use that
|
37
|
+
send(method, column, options)
|
38
|
+
|
39
|
+
else # final ultimate fallback: use rails' generic input method
|
40
|
+
# for textual fields we pass different options
|
41
|
+
text_types = %i[text string integer float decimal]
|
42
|
+
options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
|
43
|
+
if column.column.type == :string && options[:maxlength].blank?
|
44
|
+
options[:maxlength] = column.column.limit
|
45
|
+
options[:size] ||= options[:maxlength].to_i > 30 ? 30 : options[:maxlength]
|
52
46
|
end
|
47
|
+
options[:value] = format_number_value(record.send(column.name), column.options) if column.number?
|
48
|
+
text_field(:record, column.name, options.merge(column.options).except(:format))
|
53
49
|
end
|
54
50
|
rescue StandardError => e
|
55
51
|
logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
|
56
52
|
raise e
|
57
53
|
end
|
58
54
|
|
59
|
-
def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil)
|
55
|
+
def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil) # rubocop:disable Metrics/ParameterLists
|
60
56
|
if add_class
|
61
57
|
col_class = []
|
62
58
|
col_class << 'required' if column.required?
|
@@ -134,7 +130,7 @@ module ActiveScaffold
|
|
134
130
|
url_params = url_params.except(:parent_scaffold, :association, nested.param_name)
|
135
131
|
end
|
136
132
|
if scope
|
137
|
-
url_params[:parent_controller] ||= url_params[:controller].gsub(%r{
|
133
|
+
url_params[:parent_controller] ||= url_params[:controller].gsub(%r{^/}, '')
|
138
134
|
url_params[:controller] = subform_controller.controller_path
|
139
135
|
url_params[:scope] = scope
|
140
136
|
url_params[:parent_id] = params[:parent_id] || params[:id]
|
@@ -152,8 +148,8 @@ module ActiveScaffold
|
|
152
148
|
{}
|
153
149
|
end
|
154
150
|
|
155
|
-
def render_column(column, record, renders_as, scope = nil, only_value = false, col_class = nil)
|
156
|
-
if partial = override_form_field_partial(column)
|
151
|
+
def render_column(column, record, renders_as, scope = nil, only_value = false, col_class = nil) # rubocop:disable Metrics/ParameterLists
|
152
|
+
if (partial = override_form_field_partial(column))
|
157
153
|
render :partial => partial, :locals => {:column => column, :only_value => only_value, :scope => scope, :col_class => col_class, :record => record}
|
158
154
|
elsif renders_as == :field || override_form_field?(column)
|
159
155
|
form_attribute(column, record, scope, only_value, col_class)
|
@@ -179,12 +175,14 @@ module ActiveScaffold
|
|
179
175
|
else
|
180
176
|
field = active_scaffold_input_for column, scope, column_options
|
181
177
|
end
|
178
|
+
if field
|
179
|
+
field << loading_indicator_tag(:action => :render_field, :id => params[:id]) if column.update_columns
|
180
|
+
field << content_tag(:span, column.description, :class => 'description') if column.description.present?
|
181
|
+
end
|
182
182
|
|
183
183
|
content_tag :dl, attributes do
|
184
|
-
|
185
|
-
|
186
|
-
#{content_tag :span, column.description, :class => 'description' if column.description.present?}
|
187
|
-
</dd>).html_safe
|
184
|
+
content_tag(:dt, label_tag(label_for(column, column_options), form_column_label(column))) <<
|
185
|
+
content_tag(:dd, field)
|
188
186
|
end
|
189
187
|
end
|
190
188
|
|
@@ -192,6 +190,10 @@ module ActiveScaffold
|
|
192
190
|
options[:id] unless column.form_ui == :select && column.association&.collection?
|
193
191
|
end
|
194
192
|
|
193
|
+
def form_column_label(column)
|
194
|
+
column.label
|
195
|
+
end
|
196
|
+
|
195
197
|
def subform_label(column, hidden)
|
196
198
|
column.label unless hidden
|
197
199
|
end
|
@@ -276,9 +278,8 @@ module ActiveScaffold
|
|
276
278
|
end
|
277
279
|
|
278
280
|
def active_scaffold_select_name_with_multiple(options)
|
279
|
-
if options[:multiple]
|
280
|
-
|
281
|
-
end
|
281
|
+
return if !options[:multiple] || options[:name].to_s.ends_with?('[]')
|
282
|
+
options[:name] = "#{options[:name]}[]"
|
282
283
|
end
|
283
284
|
|
284
285
|
def active_scaffold_input_singular_association(column, html_options, options = {})
|
@@ -303,10 +304,24 @@ module ActiveScaffold
|
|
303
304
|
collection_select(:record, method, select_options, :id, column.options[:label_method] || :to_label, options, html_options)
|
304
305
|
end
|
305
306
|
html << active_scaffold_refresh_link(column, html_options, record) if column.options[:refresh_link]
|
307
|
+
html << active_scaffold_new_record_subform(column, record, html_options) if column.options[:add_new]
|
306
308
|
html
|
307
309
|
end
|
308
310
|
|
309
|
-
def
|
311
|
+
def active_scaffold_new_record_subform(column, record, html_options)
|
312
|
+
subform_attrs = active_scaffold_subform_attributes(column).merge(style: 'display: none')
|
313
|
+
scope = html_options[:name].scan(/record(.*)\[#{column.name}\]/).dig(0, 0)
|
314
|
+
new_record = build_associated(column.association, record)
|
315
|
+
subform = render(partial: subform_partial_for_column(column), locals: {column: column, parent_record: record, associated: [], show_blank_record: new_record, scope: scope})
|
316
|
+
html = content_tag(:div, subform, subform_attrs)
|
317
|
+
html << active_scaffold_show_new_subform_link(column, record, html_options[:id], subform_attrs[:id])
|
318
|
+
end
|
319
|
+
|
320
|
+
def active_scaffold_show_new_subform_link(column, record, select_id, subform_id)
|
321
|
+
link_to(as_(:create_new), '#', data: {select_id: select_id, subform_id: subform_id, subform_text: as_(:add_existing)}, class: 'show-new-subform')
|
322
|
+
end
|
323
|
+
|
324
|
+
def active_scaffold_file_with_remove_link(column, options, content, remove_file_prefix, controls_class, &block) # rubocop:disable Metrics/ParameterLists
|
310
325
|
options = active_scaffold_input_text_options(options.merge(column.options))
|
311
326
|
if content
|
312
327
|
active_scaffold_file_with_content(column, content, options, remove_file_prefix, controls_class, &block)
|
@@ -329,12 +344,13 @@ module ActiveScaffold
|
|
329
344
|
object_name, method = options[:name].split(/\[(#{column.name})\]/)
|
330
345
|
method.sub!(/#{column.name}/, "#{remove_file_prefix}\\0")
|
331
346
|
fields = block_given? ? yield : ''
|
347
|
+
link_key = options[:multiple] ? :remove_files : :remove_file
|
332
348
|
input = file_field(:record, column.name, options.merge(:onchange => js_dont_remove_file_code))
|
333
349
|
content_tag(:div, class: controls_class) do
|
334
350
|
content_tag(:div) do
|
335
351
|
safe_join [content, ' | ', fields,
|
336
352
|
hidden_field(object_name, method, :value => 'false', class: 'remove_file'),
|
337
|
-
content_tag(:a, as_(
|
353
|
+
content_tag(:a, as_(link_key), :href => '#', :onclick => js_remove_file_code)]
|
338
354
|
end << content_tag(:div, input, :style => 'display: none')
|
339
355
|
end
|
340
356
|
end
|
@@ -385,11 +401,11 @@ module ActiveScaffold
|
|
385
401
|
label_method = column.options[:label_method] || :to_label
|
386
402
|
html = hidden_field_tag("#{options[:name]}[]", '', :id => nil)
|
387
403
|
html << content_tag(:ul, options.merge(:class => "#{options[:class]} checkbox-list#{' draggable-lists' if column.options[:draggable_lists]}")) do
|
388
|
-
content =
|
404
|
+
content = []
|
389
405
|
select_options.each_with_index do |option, i|
|
390
406
|
content << active_scaffold_checkbox_option(option, label_method, associated_ids, :name => "#{options[:name]}[]", :id => "#{options[:id]}_#{i}_id")
|
391
407
|
end
|
392
|
-
content
|
408
|
+
safe_join content
|
393
409
|
end
|
394
410
|
html
|
395
411
|
end
|
@@ -454,10 +470,20 @@ module ActiveScaffold
|
|
454
470
|
end
|
455
471
|
|
456
472
|
selected = record.send(column.association.name)&.id if column.association
|
457
|
-
|
458
|
-
|
473
|
+
if options.present?
|
474
|
+
radios = options.map do |option|
|
475
|
+
active_scaffold_radio_option(option, selected, column, html_options)
|
476
|
+
end
|
477
|
+
if column.options[:include_blank]
|
478
|
+
label = column.options[:include_blank]
|
479
|
+
label = as_(column.options[:include_blank]) if column.options[:include_blank].is_a?(Symbol)
|
480
|
+
radios.prepend content_tag(:label, radio_button(:record, column.name, '', html_options.merge(id: nil)) + label)
|
481
|
+
end
|
482
|
+
safe_join radios
|
483
|
+
else
|
484
|
+
content_tag(:span, as_(:no_options), :class => "#{html_options[:class]} no-options", :id => html_options[:id]) <<
|
485
|
+
hidden_field_tag(html_options[:name], '', :id => nil)
|
459
486
|
end
|
460
|
-
safe_join radios
|
461
487
|
end
|
462
488
|
|
463
489
|
def active_scaffold_input_checkbox(column, options)
|
@@ -519,16 +545,17 @@ module ActiveScaffold
|
|
519
545
|
|
520
546
|
# A color picker
|
521
547
|
def active_scaffold_input_color(column, options)
|
548
|
+
html = []
|
522
549
|
options = active_scaffold_input_text_options(options)
|
523
550
|
if column.column&.null
|
524
551
|
no_color = options[:object].send(column.name).nil?
|
525
552
|
method = no_color ? :hidden_field : :color_field
|
526
|
-
html
|
553
|
+
html << content_tag(:label, check_box_tag('disable', '1', no_color, id: nil, name: nil, class: 'no-color') << " #{as_ column.options[:no_color] || :no_color}")
|
527
554
|
else
|
528
555
|
method = :color_field
|
529
|
-
html = ''.html_safe
|
530
556
|
end
|
531
557
|
html << send(method, :record, column.name, options.merge(column.options).except(:format, :no_color))
|
558
|
+
safe_join html
|
532
559
|
end
|
533
560
|
|
534
561
|
#
|
@@ -539,8 +566,8 @@ module ActiveScaffold
|
|
539
566
|
record = options.delete(:object)
|
540
567
|
select_options = []
|
541
568
|
select_options << [as_(:_select_), nil] if !column.virtual? && column.column.null
|
542
|
-
select_options << [as_(:true), true]
|
543
|
-
select_options << [as_(:false), false]
|
569
|
+
select_options << [as_(:true), true] # rubocop:disable Lint/BooleanSymbol
|
570
|
+
select_options << [as_(:false), false] # rubocop:disable Lint/BooleanSymbol
|
544
571
|
|
545
572
|
select_tag(options[:name], options_for_select(select_options, record.send(column.name)), options)
|
546
573
|
end
|
@@ -636,12 +663,12 @@ module ActiveScaffold
|
|
636
663
|
remote_controller = active_scaffold_controller_for(record_select_config.model).controller_path
|
637
664
|
options[:controller] = remote_controller
|
638
665
|
options.merge!(active_scaffold_input_text_options)
|
639
|
-
record_select_field(options[:name],
|
666
|
+
record_select_field(options[:name], nil, options)
|
640
667
|
else
|
641
668
|
select_options = sorted_association_options_find(nested.association, nil, record)
|
642
669
|
select_options ||= active_scaffold_config.model.all
|
643
670
|
select_options = options_from_collection_for_select(select_options, :id, :to_label)
|
644
|
-
select_tag 'associated_id', (
|
671
|
+
select_tag 'associated_id', (content_tag(:option, as_(:_select_), value: '') + select_options) unless select_options.empty?
|
645
672
|
end
|
646
673
|
end
|
647
674
|
|
@@ -654,55 +681,62 @@ module ActiveScaffold
|
|
654
681
|
end
|
655
682
|
|
656
683
|
# Try to get numerical constraints from model's validators
|
657
|
-
def
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
684
|
+
def column_numerical_constraints(column, options)
|
685
|
+
validators = column.active_record_class.validators.select do |v|
|
686
|
+
v.is_a?(ActiveModel::Validations::NumericalityValidator) && v.attributes.include?(column.name)
|
687
|
+
end
|
688
|
+
|
689
|
+
equal_validator = validators.find { |v| v.options[:equal_to] }
|
690
|
+
# If there is equal_to constraint - use it (unless otherwise specified by user)
|
691
|
+
if equal_validator && !(options[:min] || options[:max])
|
692
|
+
equal_to = equal_validator.options[:equal_to]
|
693
|
+
return {min: equal_to, max: equal_to}
|
694
|
+
end
|
695
|
+
|
696
|
+
numerical_constraints = {}
|
697
|
+
|
698
|
+
# find minimum and maximum from validators
|
699
|
+
# we can safely modify :min and :max by 1 for :greater_tnan or :less_than value only for integer values
|
700
|
+
only_integer = column.column.type == :integer if column.column
|
701
|
+
only_integer ||= validators.find { |v| v.options[:only_integer] }.present?
|
702
|
+
margin = only_integer ? 1 : 0
|
703
|
+
|
704
|
+
# Minimum
|
705
|
+
unless options[:min]
|
706
|
+
min = validators.map { |v| v.options[:greater_than_or_equal] }.compact.max
|
707
|
+
greater_than = validators.map { |v| v.options[:greater_than] }.compact.max
|
708
|
+
numerical_constraints[:min] = [min, (greater_than + margin if greater_than)].compact.max
|
709
|
+
end
|
710
|
+
|
711
|
+
# Maximum
|
712
|
+
unless options[:max]
|
713
|
+
max = validators.map { |v| v.options[:less_than_or_equal] }.compact.min
|
714
|
+
less_than = validators.map { |v| v.options[:less_than] }.compact.min
|
715
|
+
numerical_constraints[:max] = [max, (less_than - margin if less_than)].compact.min
|
716
|
+
end
|
717
|
+
|
718
|
+
# Set step = 2 for column values restricted to be odd or even (but only if minimum is set)
|
719
|
+
unless options[:step]
|
720
|
+
only_odd_valid = validators.any? { |v| v.options[:odd] }
|
721
|
+
only_even_valid = validators.any? { |v| v.options[:even] } unless only_odd_valid
|
722
|
+
if !only_integer
|
723
|
+
numerical_constraints[:step] ||= "0.#{'0' * (column.column.scale - 1)}1" if column.column&.scale.to_i.positive?
|
724
|
+
elsif options[:min] && options[:min].respond_to?(:even?) && (only_odd_valid || only_even_valid)
|
725
|
+
numerical_constraints[:step] = 2
|
726
|
+
numerical_constraints[:min] += 1 if only_odd_valid && options[:min].even?
|
727
|
+
numerical_constraints[:min] += 1 if only_even_valid && options[:min].odd?
|
662
728
|
end
|
663
|
-
|
664
|
-
|
665
|
-
# If there is equal_to constraint - use it (unless otherwise specified by user)
|
666
|
-
if equal_to && !(options[:min] || options[:max])
|
667
|
-
numerical_constraints[:min] = numerical_constraints[:max] = equal_to
|
668
|
-
else # find minimum and maximum from validators
|
669
|
-
# we can safely modify :min and :max by 1 for :greater_tnan or :less_than value only for integer values
|
670
|
-
only_integer = column.column.type == :integer if column.column
|
671
|
-
only_integer ||= validators.find { |v| v.options[:only_integer] }.present?
|
672
|
-
margin = only_integer ? 1 : 0
|
673
|
-
|
674
|
-
# Minimum
|
675
|
-
unless options[:min]
|
676
|
-
min = validators.map { |v| v.options[:greater_than_or_equal] }.compact.max
|
677
|
-
greater_than = validators.map { |v| v.options[:greater_than] }.compact.max
|
678
|
-
numerical_constraints[:min] = [min, (greater_than + margin if greater_than)].compact.max
|
679
|
-
end
|
680
|
-
|
681
|
-
# Maximum
|
682
|
-
unless options[:max]
|
683
|
-
max = validators.map { |v| v.options[:less_than_or_equal] }.compact.min
|
684
|
-
less_than = validators.map { |v| v.options[:less_than] }.compact.min
|
685
|
-
numerical_constraints[:max] = [max, (less_than - margin if less_than)].compact.min
|
686
|
-
end
|
729
|
+
numerical_constraints[:step] ||= 'any' unless only_integer
|
730
|
+
end
|
687
731
|
|
688
|
-
|
689
|
-
|
690
|
-
only_odd_valid = validators.any? { |v| v.options[:odd] }
|
691
|
-
only_even_valid = validators.any? { |v| v.options[:even] } unless only_odd_valid
|
692
|
-
if !only_integer
|
693
|
-
numerical_constraints[:step] ||= "0.#{'0' * (column.column.scale - 1)}1" if column.column&.scale.to_i.positive?
|
694
|
-
elsif options[:min] && options[:min].respond_to?(:even?) && (only_odd_valid || only_even_valid)
|
695
|
-
numerical_constraints[:step] = 2
|
696
|
-
numerical_constraints[:min] += 1 if only_odd_valid && options[:min].even?
|
697
|
-
numerical_constraints[:min] += 1 if only_even_valid && options[:min].odd?
|
698
|
-
end
|
699
|
-
numerical_constraints[:step] ||= 'any' unless only_integer
|
700
|
-
end
|
701
|
-
end
|
732
|
+
numerical_constraints
|
733
|
+
end
|
702
734
|
|
703
|
-
|
735
|
+
def numerical_constraints_for_column(column, options)
|
736
|
+
constraints = Rails.cache.fetch("#{column.cache_key}#numerical_constarints") do
|
737
|
+
column_numerical_constraints(column, options)
|
704
738
|
end
|
705
|
-
|
739
|
+
constraints.merge(options)
|
706
740
|
end
|
707
741
|
end
|
708
742
|
end
|