active_scaffold 3.6.0.pre → 3.6.0.rc1

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.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +39 -0
  3. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  4. data/app/assets/javascripts/jquery/active_scaffold.js +35 -4
  5. data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
  6. data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
  7. data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
  8. data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
  9. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  11. data/config/locales/de.yml +2 -1
  12. data/config/locales/en.yml +1 -0
  13. data/config/locales/es.yml +1 -0
  14. data/config/locales/fr.yml +2 -1
  15. data/config/locales/hu.yml +1 -0
  16. data/config/locales/ja.yml +1 -0
  17. data/config/locales/ru.yml +1 -0
  18. data/lib/active_scaffold.rb +8 -3
  19. data/lib/active_scaffold/actions/common_search.rb +11 -8
  20. data/lib/active_scaffold/actions/core.rb +79 -51
  21. data/lib/active_scaffold/actions/create.rb +27 -27
  22. data/lib/active_scaffold/actions/delete.rb +1 -1
  23. data/lib/active_scaffold/actions/field_search.rb +52 -42
  24. data/lib/active_scaffold/actions/list.rb +106 -23
  25. data/lib/active_scaffold/actions/nested.rb +59 -42
  26. data/lib/active_scaffold/actions/show.rb +3 -3
  27. data/lib/active_scaffold/actions/subform.rb +9 -16
  28. data/lib/active_scaffold/actions/update.rb +95 -77
  29. data/lib/active_scaffold/attribute_params.rb +93 -68
  30. data/lib/active_scaffold/bridges/active_storage.rb +6 -0
  31. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
  32. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
  33. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
  34. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
  35. data/lib/active_scaffold/bridges/bitfields.rb +1 -0
  36. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  37. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +6 -0
  38. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  39. data/lib/active_scaffold/bridges/date_picker/helper.rb +46 -41
  40. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  41. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +2 -2
  42. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  43. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +3 -1
  44. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  45. data/lib/active_scaffold/bridges/record_select/helpers.rb +3 -7
  46. data/lib/active_scaffold/bridges/shared/date_bridge.rb +19 -18
  47. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  48. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +20 -3
  49. data/lib/active_scaffold/config/base.rb +58 -34
  50. data/lib/active_scaffold/config/core.rb +31 -12
  51. data/lib/active_scaffold/config/delete.rb +12 -1
  52. data/lib/active_scaffold/config/list.rb +17 -7
  53. data/lib/active_scaffold/config/mark.rb +1 -1
  54. data/lib/active_scaffold/configurable.rb +5 -3
  55. data/lib/active_scaffold/constraints.rb +21 -19
  56. data/lib/active_scaffold/core.rb +35 -26
  57. data/lib/active_scaffold/data_structures/action_columns.rb +1 -1
  58. data/lib/active_scaffold/data_structures/action_link.rb +34 -16
  59. data/lib/active_scaffold/data_structures/action_links.rb +9 -11
  60. data/lib/active_scaffold/data_structures/association/abstract.rb +35 -13
  61. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  62. data/lib/active_scaffold/data_structures/association/active_record.rb +5 -1
  63. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  64. data/lib/active_scaffold/data_structures/column.rb +49 -58
  65. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  66. data/lib/active_scaffold/data_structures/nested_info.rb +20 -18
  67. data/lib/active_scaffold/data_structures/sorting.rb +5 -0
  68. data/lib/active_scaffold/delayed_setup.rb +16 -6
  69. data/lib/active_scaffold/extensions/action_controller_rendering.rb +1 -1
  70. data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
  71. data/lib/active_scaffold/extensions/cow_proxy.rb +50 -2
  72. data/lib/active_scaffold/extensions/localize.rb +3 -1
  73. data/lib/active_scaffold/extensions/routing_mapper.rb +2 -2
  74. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  75. data/lib/active_scaffold/finder.rb +81 -46
  76. data/lib/active_scaffold/helpers/action_link_helpers.rb +47 -21
  77. data/lib/active_scaffold/helpers/association_helpers.rb +13 -11
  78. data/lib/active_scaffold/helpers/controller_helpers.rb +14 -11
  79. data/lib/active_scaffold/helpers/form_column_helpers.rb +133 -99
  80. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  81. data/lib/active_scaffold/helpers/id_helpers.rb +4 -0
  82. data/lib/active_scaffold/helpers/list_column_helpers.rb +76 -49
  83. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  84. data/lib/active_scaffold/helpers/search_column_helpers.rb +25 -30
  85. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  86. data/lib/active_scaffold/helpers/view_helpers.rb +31 -22
  87. data/lib/active_scaffold/orm_checks.rb +2 -2
  88. data/lib/active_scaffold/paginator.rb +1 -3
  89. data/lib/active_scaffold/registry.rb +11 -0
  90. data/lib/active_scaffold/responds_to_parent.rb +6 -5
  91. data/lib/active_scaffold/tableless.rb +6 -8
  92. data/lib/active_scaffold/version.rb +1 -1
  93. data/shoulda_macros/macros.rb +3 -1
  94. data/test/bridges/paperclip_test.rb +1 -1
  95. data/test/company.rb +2 -2
  96. data/test/data_structures/action_columns_test.rb +2 -2
  97. data/test/data_structures/column_test.rb +3 -6
  98. data/test/data_structures/columns_test.rb +2 -2
  99. data/test/extensions/active_record_test.rb +4 -4
  100. data/test/extensions/routing_mapper_test.rb +2 -2
  101. data/test/helpers/list_column_helpers_test.rb +3 -1
  102. data/test/misc/active_record_permissions_test.rb +2 -2
  103. data/test/misc/attribute_params_test.rb +4 -0
  104. data/test/misc/configurable_test.rb +10 -10
  105. data/test/misc/convert_numbers_format_test.rb +4 -0
  106. data/test/mock_app/app/assets/config/manifest.js +0 -0
  107. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  108. data/test/mock_app/app/controllers/people_controller.rb +3 -1
  109. data/test/mock_app/config/application.rb +1 -0
  110. data/test/mock_app/config/routes.rb +4 -1
  111. data/test/mock_app/db/schema.rb +2 -0
  112. data/test/performance/list_cars_performance_test.rb +34 -0
  113. data/test/performance/list_people_performance_test.rb +31 -0
  114. data/test/performance_test_help.rb +3 -0
  115. data/test/test_helper.rb +2 -1
  116. metadata +22 -12
  117. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  118. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -5
@@ -57,7 +57,7 @@ module ActiveScaffold
57
57
 
58
58
  def active_scaffold_human_condition_boolean(column, value)
59
59
  attribute = column.active_record_class.human_attribute_name(column.name)
60
- label = as_(ActiveScaffold::Core.column_type_cast(value, column.column) ? :true : :false)
60
+ label = as_(ActiveScaffold::Core.column_type_cast(value, column.column) ? :true : :false) # rubocop:disable Lint/BooleanSymbol
61
61
  as_(:boolean, :scope => :human_conditions, :column => attribute, :value => label)
62
62
  end
63
63
  alias active_scaffold_human_condition_checkbox active_scaffold_human_condition_boolean
@@ -10,6 +10,10 @@ module ActiveScaffold
10
10
  'as_' + id_from_controller(controller)
11
11
  end
12
12
 
13
+ def nested?
14
+ false # will be overrided in AS controllers with helper_method
15
+ end
16
+
13
17
  def nested_parent_id
14
18
  nested_parent_record.id
15
19
  end
@@ -10,7 +10,7 @@ module ActiveScaffold
10
10
  else
11
11
  value = nil
12
12
  end
13
- value = ' '.html_safe if value.nil? || value.blank? # fix for IE 6
13
+ value = ' '.html_safe if value.nil? || value.blank? # fix for IE 6 # rubocop:disable Rails/OutputSafety
14
14
  value
15
15
  rescue StandardError => e
16
16
  logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}, record: #{record.inspect}"
@@ -19,7 +19,7 @@ module ActiveScaffold
19
19
 
20
20
  def get_column_method(record, column)
21
21
  # check for an override helper
22
- column.list_method ||= begin
22
+ ActiveScaffold::Registry.cache :column_methods, column.cache_key do
23
23
  if (method = column_override(column))
24
24
  # we only pass the record as the argument. we previously also passed the formatted_value,
25
25
  # but mike perham pointed out that prohibited the usage of overrides to improve on the
@@ -47,8 +47,8 @@ module ActiveScaffold
47
47
  render_action_link(link, record, :link => text, :authorized => authorized, :not_authorized_reason => reason)
48
48
  elsif inplace_edit?(record, column)
49
49
  active_scaffold_inplace_edit(record, column, :formatted_column => text)
50
- elsif active_scaffold_config.actions.include?(:list) && active_scaffold_config.list.wrap_tag
51
- content_tag active_scaffold_config.list.wrap_tag, text
50
+ elsif column_wrap_tag
51
+ content_tag column_wrap_tag, text
52
52
  else
53
53
  text
54
54
  end
@@ -57,6 +57,11 @@ module ActiveScaffold
57
57
  raise e
58
58
  end
59
59
 
60
+ def column_wrap_tag
61
+ return @_column_wrap_tag if defined? @_column_wrap_tag
62
+ @_column_wrap_tag = (active_scaffold_config.list.wrap_tag if active_scaffold_config.actions.include?(:list))
63
+ end
64
+
60
65
  # There are two basic ways to clean a column's value: h() and sanitize(). The latter is useful
61
66
  # when the column contains *valid* html data, and you want to just disable any scripting. People
62
67
  # can always use field overrides to clean data one way or the other, but having this override
@@ -127,20 +132,21 @@ module ActiveScaffold
127
132
 
128
133
  # the naming convention for overriding column types with helpers
129
134
  def override_column_ui(list_ui)
130
- @_column_ui_overrides ||= {}
131
- return @_column_ui_overrides[list_ui] if @_column_ui_overrides.include? list_ui
132
- method = "active_scaffold_column_#{list_ui}"
133
- @_column_ui_overrides[list_ui] = (method if respond_to? method)
135
+ ActiveScaffold::Registry.cache :column_ui_overrides, list_ui do
136
+ method = "active_scaffold_column_#{list_ui}"
137
+ method if respond_to? method
138
+ end
134
139
  end
135
140
  alias override_column_ui? override_column_ui
136
141
 
137
142
  ##
138
143
  ## Formatting
139
144
  ##
145
+ FORM_UI_WITH_OPTIONS = %i[select radio].freeze
140
146
  def format_column_value(record, column, value = nil)
141
147
  value ||= record.send(column.name) unless record.nil?
142
148
  if column.association.nil?
143
- if %i[select radio].include?(column.form_ui) && column.options[:options]
149
+ if FORM_UI_WITH_OPTIONS.include?(column.form_ui) && column.options[:options]
144
150
  text, val = column.options[:options].find { |t, v| (v.nil? ? t : v).to_s == value.to_s }
145
151
  value = active_scaffold_translated_option(column, text, val).first if text
146
152
  end
@@ -153,7 +159,7 @@ module ActiveScaffold
153
159
  end
154
160
  else
155
161
  if column.association.collection?
156
- associated_size = value.size if column.associated_number? # get count before cache association
162
+ associated_size = column_association_size(record, column, value) if column.associated_number? # get count before cache association
157
163
  if column.association.respond_to_target? && !value.loaded?
158
164
  cache_association(record.association(column.name), column, associated_size)
159
165
  end
@@ -162,20 +168,27 @@ module ActiveScaffold
162
168
  end
163
169
  end
164
170
 
171
+ def column_association_size(record, column, value)
172
+ cached_counts = @counts&.dig(column.name)
173
+ key = column.association.primary_key if count_on_association_class?(column)
174
+ cached_counts ? cached_counts[record.send(key || :id)] || 0 : value.size
175
+ end
176
+
165
177
  def format_number_value(value, options = {})
166
178
  if value
167
- value = case options[:format]
168
- when :size
169
- number_to_human_size(value, options[:i18n_options] || {})
170
- when :percentage
171
- number_to_percentage(value, options[:i18n_options] || {})
172
- when :currency
173
- number_to_currency(value, options[:i18n_options] || {})
174
- when :i18n_number
175
- send("number_with_#{value.is_a?(Integer) ? 'delimiter' : 'precision'}", value, options[:i18n_options] || {})
176
- else
177
- value
178
- end
179
+ value =
180
+ case options[:format]
181
+ when :size
182
+ number_to_human_size(value, options[:i18n_options] || {})
183
+ when :percentage
184
+ number_to_percentage(value, options[:i18n_options] || {})
185
+ when :currency
186
+ number_to_currency(value, options[:i18n_options] || {})
187
+ when :i18n_number
188
+ send("number_with_#{value.is_a?(Integer) ? 'delimiter' : 'precision'}", value, options[:i18n_options] || {})
189
+ else
190
+ value
191
+ end
179
192
  end
180
193
  clean_column_value(value)
181
194
  end
@@ -196,18 +209,26 @@ module ActiveScaffold
196
209
  end
197
210
  end
198
211
 
212
+ def association_join_text(column = nil)
213
+ column_value = column&.association_join_text
214
+ return column_value if column_value
215
+ return @_association_join_text if defined? @_association_join_text
216
+ @_association_join_text = active_scaffold_config.list.association_join_text
217
+ end
218
+
199
219
  def format_collection_association_value(value, column, label_method, size)
200
- if column.associated_limit.nil?
220
+ associated_limit = column.associated_limit
221
+ if associated_limit.nil?
201
222
  firsts = value.collect(&label_method)
202
- safe_join firsts, active_scaffold_config.list.association_join_text
203
- elsif column.associated_limit.zero?
223
+ safe_join firsts, association_join_text(column)
224
+ elsif associated_limit.zero?
204
225
  size if column.associated_number?
205
226
  else
206
- firsts = value.loaded? ? value[0, column.associated_limit] : value.limit(column.associated_limit)
227
+ firsts = value.loaded? ? value[0, associated_limit] : value.limit(associated_limit)
207
228
  firsts = firsts.map(&label_method)
208
- firsts << '…' if value.size > column.associated_limit
209
- text = safe_join firsts, active_scaffold_config.list.association_join_text
210
- text << " (#{size})" if column.associated_number? && column.associated_limit && value.size > column.associated_limit
229
+ firsts << '…' if value.size > associated_limit
230
+ text = safe_join firsts, association_join_text(column)
231
+ text << " (#{size})" if column.associated_number? && associated_limit && value.size > associated_limit
211
232
  text
212
233
  end
213
234
  end
@@ -237,7 +258,7 @@ module ActiveScaffold
237
258
  empty_field_text
238
259
  elsif column_value.is_a?(Time) || column_value.is_a?(Date)
239
260
  l(column_value, :format => options[:format] || :default)
240
- elsif [FalseClass, TrueClass].include?(column_value.class)
261
+ elsif !!column_value == column_value # rubocop:disable Style/DoubleNegation fast check for boolean
241
262
  as_(column_value.to_s.to_sym)
242
263
  else
243
264
  column_value.to_s
@@ -246,15 +267,21 @@ module ActiveScaffold
246
267
  end
247
268
 
248
269
  def cache_association(association, column, size)
270
+ associated_limit = column.associated_limit
249
271
  # we are not using eager loading, cache firsts records in order not to query the database for whole association in a future
250
- if column.associated_limit.nil?
272
+ if associated_limit.nil?
251
273
  logger.warn "ActiveScaffold: Enable eager loading for #{column.name} association to reduce SQL queries"
252
- elsif column.associated_limit.positive?
274
+ elsif associated_limit.positive?
253
275
  # load at least one record more, is needed to display '...'
254
- association.target = association.reader.limit(column.associated_limit + 1).select(column.select_associated_columns || "#{association.klass.quoted_table_name}.*").to_a
276
+ association.target = association.reader.limit(associated_limit + 1).select(column.select_associated_columns || "#{association.klass.quoted_table_name}.*").to_a
255
277
  elsif @cache_associations
256
278
  # set array with at least one element if size > 0, so blank? or present? works, saving [nil] may cause exceptions
257
- association.target = size.to_i.zero? ? [] : [association.klass.new]
279
+ association.target =
280
+ if size.to_i.zero?
281
+ []
282
+ else
283
+ ActiveScaffold::Registry.cache(:cached_empty_association, association.klass) { [association.klass.new] }
284
+ end
258
285
  end
259
286
  end
260
287
 
@@ -265,14 +292,9 @@ module ActiveScaffold
265
292
  def inplace_edit?(record, column)
266
293
  return unless column.inplace_edit
267
294
  if controller.respond_to?(:update_authorized?, true)
268
- if controller.method(:update_authorized?).parameters.size == 2
269
- return Array(controller.send(:update_authorized?, record, column.name))[0]
270
- else
271
- ActiveSupport::Deprecation.warn 'add column = nil parameter to update_authorized? on your controller'
272
- editable = Array(controller.send(:update_authorized?, record))[0]
273
- end
295
+ return Array(controller.send(:update_authorized?, record, column.name))[0]
274
296
  end
275
- editable || record.authorized_for?(:crud_type => :update, :column => column.name)
297
+ record.authorized_for?(:crud_type => :update, :column => column.name)
276
298
  end
277
299
 
278
300
  def inplace_edit_cloning?(column)
@@ -280,17 +302,21 @@ module ActiveScaffold
280
302
  end
281
303
 
282
304
  def active_scaffold_inplace_edit_tag_options(record, column)
283
- id_options = {:id => record.id.to_s, :action => 'update_column', :name => column.name.to_s}
284
- tag_options = {:id => element_cell_id(id_options), :class => 'in_place_editor_field',
285
- :title => as_(:click_to_edit), :data => {:ie_id => record.to_param}}
305
+ @_inplace_edit_title ||= as_(:click_to_edit)
306
+ cell_id = ActiveScaffold::Registry.cache :inplace_edit_id, column.cache_key do
307
+ element_cell_id(id: '--ID--', action: 'update_column', name: column.name.to_s)
308
+ end
309
+ tag_options = {id: cell_id.sub('--ID--', record.id.to_s), class: 'in_place_editor_field',
310
+ title: @_inplace_edit_title, data: {:ie_id => record.to_param}}
286
311
  tag_options[:data][:ie_update] = column.inplace_edit if column.inplace_edit != true
287
312
  tag_options
288
313
  end
289
314
 
290
315
  def active_scaffold_inplace_edit(record, column, options = {})
291
316
  formatted_column = options[:formatted_column] || format_column_value(record, column)
292
- content_tag(:span, as_(:inplace_edit_handle), :class => 'handle') <<
293
- content_tag(:span, formatted_column, active_scaffold_inplace_edit_tag_options(record, column))
317
+ @_inplace_edit_handle ||= content_tag(:span, as_(:inplace_edit_handle), :class => 'handle')
318
+ span = content_tag(:span, formatted_column, active_scaffold_inplace_edit_tag_options(record, column))
319
+ @_inplace_edit_handle + span
294
320
  end
295
321
 
296
322
  def inplace_edit_control(column)
@@ -311,6 +337,7 @@ module ActiveScaffold
311
337
  'as_inplace_pattern'
312
338
  end
313
339
 
340
+ INPLACE_EDIT_PLURAL_FORM_UI = %i[select record_select].freeze
314
341
  def inplace_edit_data(column)
315
342
  data = {}
316
343
  data[:ie_url] = url_for(params_for(:action => 'update_column', :column => column.name, :id => '__id__'))
@@ -329,7 +356,7 @@ module ActiveScaffold
329
356
  data[:ie_mode] = :clone
330
357
  elsif column.inplace_edit == :ajax
331
358
  url = url_for(params_for(:controller => params_for[:controller], :action => 'render_field', :id => '__id__', :update_column => column.name))
332
- plural = column.association&.collection? && !override_form_field?(column) && %i[select record_select].include?(column.form_ui)
359
+ plural = column.association&.collection? && !override_form_field?(column) && INPLACE_EDIT_PLURAL_FORM_UI.include?(column.form_ui)
333
360
  data[:ie_render_url] = url
334
361
  data[:ie_mode] = :ajax
335
362
  data[:ie_plural] = plural
@@ -368,8 +395,8 @@ module ActiveScaffold
368
395
  :ie_mode => :inline_checkbox,
369
396
  :ie_url => url_for(params_for(:action => 'mark', :id => '__id__'))
370
397
  }
371
- else
372
- tag_options[:data] = inplace_edit_data(column) if column.inplace_edit
398
+ elsif column.inplace_edit
399
+ tag_options[:data] = inplace_edit_data(column)
373
400
  end
374
401
  content_tag(:th, column_heading_value(column, sorting, sort_direction) + inplace_edit_control(column), tag_options)
375
402
  end
@@ -21,8 +21,8 @@ module ActiveScaffold
21
21
  start_number = 1 if start_number <= 0
22
22
  if current_page.pager.infinite?
23
23
  offsets = [20, 100]
24
- else
25
- end_number = current_page.pager.last.number if end_number > current_page.pager.last.number
24
+ elsif end_number > current_page.pager.last.number
25
+ end_number = current_page.pager.last.number
26
26
  end
27
27
 
28
28
  html = []
@@ -29,25 +29,22 @@ module ActiveScaffold
29
29
  send(method, record, options)
30
30
 
31
31
  # fallback: we get to make the decision
32
- else
33
- if column.association || column.virtual?
34
- active_scaffold_search_text(column, options)
35
-
36
- else # regular model attribute column
37
- # if we (or someone else) have created a custom render option for the column type, use that
38
- if (method = override_search(column.column.type))
39
- send(method, column, options)
40
- # if we (or someone else) have created a custom render option for the column type, use that
41
- elsif (method = override_input(column.column.type))
42
- send(method, column, options)
43
- # final ultimate fallback: use rails' generic input method
44
- else
45
- # for textual fields we pass different options
46
- text_types = %i[text string integer float decimal]
47
- options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
48
- text_field(:record, column.name, options.merge(column.options))
49
- end
50
- end
32
+ elsif column.association || column.virtual?
33
+ active_scaffold_search_text(column, options)
34
+
35
+ elsif (method = override_search(column.column.type))
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
+ elsif (method = override_input(column.column.type))
40
+ # if we (or someone else) have created a custom render option for the column type, use that
41
+ send(method, column, options)
42
+
43
+ else # final ultimate fallback: use rails' generic input method
44
+ # for textual fields we pass different options
45
+ text_types = %i[text string integer float decimal]
46
+ options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
47
+ text_field(:record, column.name, options.merge(column.options))
51
48
  end
52
49
  rescue StandardError => e
53
50
  logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
@@ -61,8 +58,10 @@ module ActiveScaffold
61
58
 
62
59
  def search_attribute(column, record)
63
60
  column_options = active_scaffold_search_options(column).merge(:object => record)
64
- field = active_scaffold_search_for column, column_options
65
- %(<dl><dt>#{label_tag search_label_for(column, column_options), search_column_label(column, record)}</dt><dd>#{field}</dd></dl>).html_safe
61
+ content_tag :dl do
62
+ content_tag(:dt, label_tag(search_label_for(column, column_options), search_column_label(column, record))) <<
63
+ content_tag(:dd, active_scaffold_search_for(column, column_options))
64
+ end
66
65
  end
67
66
 
68
67
  def search_label_for(column, options)
@@ -135,8 +134,8 @@ module ActiveScaffold
135
134
  def active_scaffold_search_boolean(column, options)
136
135
  select_options = []
137
136
  select_options << [as_(:_select_), nil]
138
- select_options << [as_(:true), true]
139
- select_options << [as_(:false), false]
137
+ select_options << [as_(:true), true] # rubocop:disable Lint/BooleanSymbol
138
+ select_options << [as_(:false), false] # rubocop:disable Lint/BooleanSymbol
140
139
 
141
140
  select_tag(options[:name], options_for_select(select_options, ActiveScaffold::Core.column_type_cast(options[:value], column.column)), :id => options[:id])
142
141
  end
@@ -166,7 +165,7 @@ module ActiveScaffold
166
165
  def active_scaffold_search_null(column, options)
167
166
  select_options = []
168
167
  select_options << [as_(:_select_), nil]
169
- select_options.concat ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] }
168
+ select_options.concat(ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] })
170
169
  select_tag(options[:name], options_for_select(select_options, options[:value]), :id => options[:id])
171
170
  end
172
171
 
@@ -187,7 +186,7 @@ module ActiveScaffold
187
186
  select_options.unshift(*comparators)
188
187
  end
189
188
  if include_null_comparators? column
190
- select_options.concat ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] }
189
+ select_options.concat(ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] })
191
190
  end
192
191
  select_options
193
192
  end
@@ -205,11 +204,7 @@ module ActiveScaffold
205
204
  opt_value, from_value, to_value = field_search_params_range_values(column)
206
205
 
207
206
  select_options = active_scaffold_search_range_comparator_options(column)
208
- if active_scaffold_search_range_string?(column)
209
- text_field_size = 15
210
- else
211
- text_field_size = 10
212
- end
207
+ text_field_size = active_scaffold_search_range_string?(column) ? 15 : 10
213
208
  opt_value ||= select_options[0][1]
214
209
 
215
210
  from_value = controller.class.condition_value_for_numeric(column, from_value)
@@ -14,12 +14,10 @@ module ActiveScaffold
14
14
  # second, check if the dev has specified a valid list_ui for this column
15
15
  elsif column.show_ui && (method = override_show_column_ui(column.show_ui))
16
16
  send(method, value_record, column)
17
+ elsif column.column && (method = override_show_column_ui(column.column.type))
18
+ send(method, value_record, column)
17
19
  else
18
- if column.column && (method = override_show_column_ui(column.column.type))
19
- send(method, value_record, column)
20
- else
21
- get_column_value(record, column)
22
- end
20
+ get_column_value(record, column)
23
21
  end
24
22
  end
25
23
 
@@ -17,8 +17,10 @@ module ActiveScaffold
17
17
  ## Delegates
18
18
  ##
19
19
 
20
- def active_scaffold_controller_for(*args)
21
- controller.class.active_scaffold_controller_for(*args)
20
+ def active_scaffold_controller_for(klass)
21
+ ActiveScaffold::Registry.cache :as_controller, klass do
22
+ controller.class.active_scaffold_controller_for(klass)
23
+ end
22
24
  end
23
25
 
24
26
  ##
@@ -56,17 +58,22 @@ module ActiveScaffold
56
58
 
57
59
  # a general-use loading indicator (the "stuff is happening, please wait" feedback)
58
60
  def loading_indicator_tag(options)
59
- image_tag 'active_scaffold/indicator.gif', :style => 'visibility:hidden;', :id => loading_indicator_id(options), :alt => 'loading indicator', :class => 'loading-indicator'
61
+ # it's call many times and we can cache same result
62
+ @_loading_indicator_path ||= image_path('active_scaffold/indicator.gif')
63
+ # it's call many times in long lists, image_tag is a bit slower
64
+ tag :img, src: @_loading_indicator_path, style: 'visibility:hidden;', id: loading_indicator_id(options), alt: 'loading indicator', class: 'loading-indicator'
60
65
  end
61
66
 
62
67
  # Creates a javascript-based link that toggles the visibility of some element on the page.
63
- # By default, it toggles the visibility of the sibling after the one it's nested in. You may pass custom javascript logic in options[:of] to change that, though. For example, you could say :of => '$("my_div_id")'.
68
+ # By default, it toggles the visibility of the sibling after the one it's nested in.
69
+ # You may pass custom javascript logic in options[:of] to change that, though. For example, you could say :of => '$("my_div_id")'.
64
70
  # You may also flag whether the other element is visible by default or not, and the initial text will adjust accordingly.
65
71
  def link_to_visibility_toggle(id, options = {})
66
- options[:default_visible] = true if options[:default_visible].nil?
67
72
  options[:hide_label] ||= as_(:hide)
68
73
  options[:show_label] ||= as_(:show_block)
69
- link_to options[:default_visible] ? options[:hide_label] : options[:show_label], '#', :data => {:show => options[:show_label], :hide => options[:hide_label], :toggable => id}, :style => 'display: none;', :class => 'as-js-button visibility-toggle'
74
+ label = options[:default_visible].nil? || options[:default_visible] ? options[:hide_label] : options[:show_label]
75
+ data = {:show => options[:show_label], :hide => options[:hide_label], :toggable => id}
76
+ link_to label, '#', :data => data, :style => 'display: none;', :class => 'as-js-button visibility-toggle'
70
77
  end
71
78
 
72
79
  def list_row_class_method(record)
@@ -80,6 +87,10 @@ module ActiveScaffold
80
87
  class_override_helper ? send(class_override_helper, record) : ''
81
88
  end
82
89
 
90
+ def list_row_attributes(tr_class, tr_id, data_refresh)
91
+ {class: "record #{tr_class}", id: tr_id, data: {refresh: data_refresh}}
92
+ end
93
+
83
94
  def column_attributes(column, record)
84
95
  method = override_helper column, 'column_attributes'
85
96
  return send(method, record) if method
@@ -87,15 +98,14 @@ module ActiveScaffold
87
98
  end
88
99
 
89
100
  def column_class(column, column_value, record)
90
- @_column_classes ||= {}
91
- @_column_classes[column.name] ||= begin
101
+ classes = ActiveScaffold::Registry.cache :column_classes, column.cache_key do
92
102
  classes = "#{column.name}-column "
93
103
  classes << 'sorted ' if active_scaffold_config.actions.include?(:list) && active_scaffold_config.list.user.sorting.sorts_on?(column)
94
104
  classes << 'numeric ' if column.number?
95
- classes << column.css_class unless column.css_class.nil? || column.css_class.is_a?(Proc)
105
+ classes << column.css_class << ' ' unless column.css_class.nil? || column.css_class.is_a?(Proc)
96
106
  classes
97
107
  end
98
- classes = "#{@_column_classes[column.name]} "
108
+ classes = classes.dup
99
109
  classes << 'empty ' if column_empty? column_value
100
110
  classes << 'in_place_editor_field ' if inplace_edit?(record, column) || column.list_ui == :marked
101
111
  if column.css_class.is_a?(Proc)
@@ -118,18 +128,23 @@ module ActiveScaffold
118
128
  classes
119
129
  end
120
130
 
131
+ def as_main_div_data
132
+ params[:eid] ? {eid: id_from_controller(params[:eid])} : {}
133
+ end
134
+
121
135
  def column_empty?(column_value)
136
+ @_empty_values ||= ['&nbsp;', empty_field_text].compact
122
137
  empty = column_value.nil?
123
138
  # column_value != false would force boolean to be cast to integer
124
139
  # when comparing to column_value of IPAddr class (PostgreSQL inet column type)
125
- # rubocop:disable Style/YodaCondition
126
- empty ||= false != column_value && column_value.blank?
127
- empty ||= ['&nbsp;', empty_field_text].include? column_value if column_value.is_a? String
140
+ empty ||= false != column_value && column_value.blank? # rubocop:disable Style/YodaCondition
141
+ empty ||= @_empty_values.include? column_value
128
142
  empty
129
143
  end
130
144
 
131
145
  def empty_field_text
132
- active_scaffold_config.list.empty_field_text if active_scaffold_config.actions.include?(:list)
146
+ return @_empty_field_text if defined? @_empty_field_text
147
+ @_empty_field_text = (active_scaffold_config.list.empty_field_text if active_scaffold_config.actions.include?(:list))
133
148
  end
134
149
 
135
150
  def as_slider(options)
@@ -150,11 +165,7 @@ module ActiveScaffold
150
165
  end
151
166
 
152
167
  def override_helper(column, suffix)
153
- hash = @_override_helpers ||= {}
154
- hash = hash[suffix] ||= {}
155
- hash = hash[column.active_record_class.name] ||= {}
156
- return hash[column.name] if hash.include? column.name
157
- hash[column.name] = begin
168
+ ActiveScaffold::Registry.cache suffix, column.cache_key do
158
169
  method_with_class = override_helper_name(column, suffix, true)
159
170
  if respond_to?(method_with_class)
160
171
  method_with_class
@@ -205,9 +216,7 @@ module ActiveScaffold
205
216
  object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model)
206
217
  object = convert_to_model(object)
207
218
 
208
- if object.class.respond_to?(:model_name)
209
- options[:object_name] ||= object.class.model_name.human.downcase
210
- end
219
+ options[:object_name] ||= object.class.model_name.human.downcase if object.class.respond_to?(:model_name)
211
220
 
212
221
  object
213
222
  end