active_scaffold 3.5.2 → 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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +66 -0
  3. data/README.md +17 -7
  4. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  5. data/app/assets/javascripts/jquery/active_scaffold.js +63 -6
  6. data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
  7. data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
  8. data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -2
  9. data/app/views/active_scaffold_overrides/_form.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +3 -2
  11. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +6 -6
  12. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
  13. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -1
  14. data/app/views/active_scaffold_overrides/_list.html.erb +2 -1
  15. data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
  16. data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -0
  17. data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
  18. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  19. data/app/views/active_scaffold_overrides/_messages.html.erb +1 -0
  20. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  21. data/app/views/active_scaffold_overrides/_render_field.js.erb +2 -1
  22. data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -1
  23. data/app/views/active_scaffold_overrides/_show_columns.html.erb +2 -2
  24. data/app/views/active_scaffold_overrides/_show_horizontal_record.html.erb +4 -4
  25. data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -1
  26. data/app/views/active_scaffold_overrides/_update_column.js.erb +2 -2
  27. data/app/views/active_scaffold_overrides/action_confirmation.html.erb +2 -2
  28. data/app/views/active_scaffold_overrides/delete.html.erb +2 -2
  29. data/app/views/active_scaffold_overrides/on_action_update.js.erb +16 -6
  30. data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
  31. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  32. data/app/views/active_scaffold_overrides/update_column.js.erb +1 -1
  33. data/config/locales/de.yml +2 -1
  34. data/config/locales/en.yml +1 -0
  35. data/config/locales/es.yml +1 -0
  36. data/config/locales/fr.yml +2 -1
  37. data/config/locales/hu.yml +1 -0
  38. data/config/locales/ja.yml +1 -0
  39. data/config/locales/ru.yml +1 -0
  40. data/lib/active_scaffold.rb +19 -16
  41. data/lib/active_scaffold/actions/common_search.rb +11 -8
  42. data/lib/active_scaffold/actions/core.rb +89 -71
  43. data/lib/active_scaffold/actions/create.rb +28 -28
  44. data/lib/active_scaffold/actions/delete.rb +3 -3
  45. data/lib/active_scaffold/actions/field_search.rb +53 -43
  46. data/lib/active_scaffold/actions/list.rb +111 -27
  47. data/lib/active_scaffold/actions/nested.rb +65 -48
  48. data/lib/active_scaffold/actions/search.rb +1 -1
  49. data/lib/active_scaffold/actions/show.rb +4 -4
  50. data/lib/active_scaffold/actions/subform.rb +12 -17
  51. data/lib/active_scaffold/actions/update.rb +96 -77
  52. data/lib/active_scaffold/active_record_permissions.rb +2 -11
  53. data/lib/active_scaffold/attribute_params.rb +104 -86
  54. data/lib/active_scaffold/bridges.rb +8 -8
  55. data/lib/active_scaffold/bridges/active_storage.rb +6 -0
  56. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
  57. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
  58. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
  59. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
  60. data/lib/active_scaffold/bridges/bitfields.rb +1 -0
  61. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  62. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
  63. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -12
  64. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
  65. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  66. data/lib/active_scaffold/bridges/chosen/helpers.rb +11 -9
  67. data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
  68. data/lib/active_scaffold/bridges/date_picker/helper.rb +49 -44
  69. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  70. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  71. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
  72. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  73. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +10 -7
  74. data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
  75. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  76. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
  77. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  78. data/lib/active_scaffold/bridges/record_select/helpers.rb +12 -16
  79. data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -19
  80. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  81. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +21 -4
  82. data/lib/active_scaffold/config/base.rb +133 -41
  83. data/lib/active_scaffold/config/core.rb +146 -18
  84. data/lib/active_scaffold/config/delete.rb +14 -1
  85. data/lib/active_scaffold/config/field_search.rb +7 -1
  86. data/lib/active_scaffold/config/form.rb +10 -1
  87. data/lib/active_scaffold/config/list.rb +39 -13
  88. data/lib/active_scaffold/config/mark.rb +4 -2
  89. data/lib/active_scaffold/config/nested.rb +16 -17
  90. data/lib/active_scaffold/config/search.rb +9 -0
  91. data/lib/active_scaffold/config/show.rb +4 -0
  92. data/lib/active_scaffold/config/update.rb +4 -0
  93. data/lib/active_scaffold/configurable.rb +14 -7
  94. data/lib/active_scaffold/constraints.rb +22 -20
  95. data/lib/active_scaffold/core.rb +68 -29
  96. data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
  97. data/lib/active_scaffold/data_structures/action_link.rb +50 -20
  98. data/lib/active_scaffold/data_structures/action_links.rb +15 -13
  99. data/lib/active_scaffold/data_structures/association/abstract.rb +41 -15
  100. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  101. data/lib/active_scaffold/data_structures/association/active_record.rb +6 -2
  102. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  103. data/lib/active_scaffold/data_structures/column.rb +75 -66
  104. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  105. data/lib/active_scaffold/data_structures/nested_info.rb +21 -19
  106. data/lib/active_scaffold/data_structures/set.rb +8 -0
  107. data/lib/active_scaffold/data_structures/sorting.rb +10 -2
  108. data/lib/active_scaffold/delayed_setup.rb +16 -5
  109. data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -2
  110. data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
  111. data/lib/active_scaffold/extensions/cow_proxy.rb +91 -0
  112. data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
  113. data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
  114. data/lib/active_scaffold/extensions/localize.rb +3 -1
  115. data/lib/active_scaffold/extensions/routing_mapper.rb +6 -45
  116. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  117. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
  118. data/lib/active_scaffold/finder.rb +104 -73
  119. data/lib/active_scaffold/helpers/action_link_helpers.rb +62 -36
  120. data/lib/active_scaffold/helpers/association_helpers.rb +21 -19
  121. data/lib/active_scaffold/helpers/controller_helpers.rb +23 -10
  122. data/lib/active_scaffold/helpers/form_column_helpers.rb +157 -121
  123. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  124. data/lib/active_scaffold/helpers/id_helpers.rb +6 -2
  125. data/lib/active_scaffold/helpers/list_column_helpers.rb +82 -53
  126. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  127. data/lib/active_scaffold/helpers/search_column_helpers.rb +29 -34
  128. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  129. data/lib/active_scaffold/helpers/view_helpers.rb +38 -35
  130. data/lib/active_scaffold/marked_model.rb +2 -2
  131. data/lib/active_scaffold/orm_checks.rb +3 -7
  132. data/lib/active_scaffold/paginator.rb +7 -7
  133. data/lib/active_scaffold/registry.rb +33 -0
  134. data/lib/active_scaffold/responds_to_parent.rb +8 -11
  135. data/lib/active_scaffold/tableless.rb +67 -65
  136. data/lib/active_scaffold/version.rb +2 -2
  137. data/lib/generators/active_scaffold/controller_generator.rb +2 -2
  138. data/lib/generators/active_scaffold/install_generator.rb +1 -1
  139. data/lib/generators/active_scaffold/resource_generator.rb +2 -2
  140. data/shoulda_macros/macros.rb +3 -1
  141. data/test/bridges/date_picker_test.rb +1 -2
  142. data/test/bridges/paperclip_test.rb +6 -6
  143. data/test/class_with_finder.rb +2 -2
  144. data/test/company.rb +4 -4
  145. data/test/config/create_test.rb +4 -2
  146. data/test/config/nested_test.rb +1 -1
  147. data/test/config/show_test.rb +1 -1
  148. data/test/config/update_test.rb +7 -6
  149. data/test/data_structures/action_columns_test.rb +2 -2
  150. data/test/data_structures/action_links_test.rb +1 -1
  151. data/test/data_structures/column_test.rb +3 -6
  152. data/test/data_structures/columns_test.rb +2 -2
  153. data/test/data_structures/sorting_test.rb +7 -0
  154. data/test/extensions/active_record_test.rb +4 -4
  155. data/test/extensions/routing_mapper_test.rb +2 -2
  156. data/test/helpers/list_column_helpers_test.rb +3 -1
  157. data/test/misc/active_record_permissions_test.rb +3 -11
  158. data/test/misc/attribute_params_test.rb +12 -8
  159. data/test/misc/calculation_test.rb +1 -1
  160. data/test/misc/configurable_test.rb +10 -10
  161. data/test/misc/constraints_test.rb +2 -2
  162. data/test/misc/convert_numbers_format_test.rb +7 -3
  163. data/test/misc/lang_test.rb +1 -1
  164. data/test/misc/parse_datetime_test.rb +3 -4
  165. data/test/misc/tableless_test.rb +6 -0
  166. data/test/mock_app/Rakefile +1 -1
  167. data/test/mock_app/app/assets/config/manifest.js +0 -0
  168. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  169. data/test/mock_app/app/controllers/people_controller.rb +3 -1
  170. data/test/mock_app/config/application.rb +2 -1
  171. data/test/mock_app/config/boot.rb +1 -1
  172. data/test/mock_app/config/environment.rb +2 -2
  173. data/test/mock_app/config/routes.rb +4 -1
  174. data/test/mock_app/db/schema.rb +2 -0
  175. data/test/performance/list_cars_performance_test.rb +34 -0
  176. data/test/performance/list_people_performance_test.rb +31 -0
  177. data/test/performance_test_help.rb +3 -0
  178. data/test/test_helper.rb +10 -2
  179. metadata +56 -15
  180. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  181. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -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,12 +10,16 @@ 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
16
20
 
17
- def nested_id(controller = params[:controller])
18
- "#{nested.parent_scaffold.controller_path}-#{nested_parent_id}-#{controller}" if nested?
21
+ def nested_id(controller = nil)
22
+ "#{nested.parent_scaffold.controller_path}-#{nested_parent_id}-#{controller || params[:parent_controller] || params[:controller]}" if nested?
19
23
  end
20
24
 
21
25
  def active_scaffold_id
@@ -10,8 +10,8 @@ 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
14
- return value
13
+ value = ' '.html_safe if value.nil? || value.blank? # fix for IE 6 # rubocop:disable Rails/OutputSafety
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}"
17
17
  raise e
@@ -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 > 0
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,23 +302,29 @@ 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)
297
323
  return unless inplace_edit?(active_scaffold_config.model, column) && inplace_edit_cloning?(column)
298
- column = column.clone
299
- column.options = column.options.clone
324
+ unless ActiveScaffold.threadsafe
325
+ column = column.dup
326
+ column.options = column.options.dup
327
+ end
300
328
  column.form_ui = :select if column.association && column.form_ui.nil?
301
329
  options = active_scaffold_input_options(column).merge(:object => column.active_record_class.new)
302
330
  options[:class] = "#{options[:class]} inplace_field"
@@ -309,6 +337,7 @@ module ActiveScaffold
309
337
  'as_inplace_pattern'
310
338
  end
311
339
 
340
+ INPLACE_EDIT_PLURAL_FORM_UI = %i[select record_select].freeze
312
341
  def inplace_edit_data(column)
313
342
  data = {}
314
343
  data[:ie_url] = url_for(params_for(:action => 'update_column', :column => column.name, :id => '__id__'))
@@ -316,7 +345,7 @@ module ActiveScaffold
316
345
  data[:ie_loading_text] = column.options[:loading_text] || as_(:loading)
317
346
  data[:ie_save_text] = column.options[:save_text] || as_(:update)
318
347
  data[:ie_saving_text] = column.options[:saving_text] || as_(:saving)
319
- data[:ie_rows] = column.options[:rows] || 5 if column.column.try(:type) == :text
348
+ data[:ie_rows] = column.options[:rows] || 5 if column.column&.type == :text
320
349
  data[:ie_cols] = column.options[:cols] if column.options[:cols]
321
350
  data[:ie_size] = column.options[:size] if column.options[:size]
322
351
  data[:ie_use_html] = column.options[:use_html] if column.options[:use_html]
@@ -327,7 +356,7 @@ module ActiveScaffold
327
356
  data[:ie_mode] = :clone
328
357
  elsif column.inplace_edit == :ajax
329
358
  url = url_for(params_for(:controller => params_for[:controller], :action => 'render_field', :id => '__id__', :update_column => column.name))
330
- plural = column.association.try(: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)
331
360
  data[:ie_render_url] = url
332
361
  data[:ie_mode] = :ajax
333
362
  data[:ie_plural] = plural
@@ -366,8 +395,8 @@ module ActiveScaffold
366
395
  :ie_mode => :inline_checkbox,
367
396
  :ie_url => url_for(params_for(:action => 'mark', :id => '__id__'))
368
397
  }
369
- else
370
- tag_options[:data] = inplace_edit_data(column) if column.inplace_edit
398
+ elsif column.inplace_edit
399
+ tag_options[:data] = inplace_edit_data(column)
371
400
  end
372
401
  content_tag(:th, column_heading_value(column, sorting, sort_direction) + inplace_edit_control(column), tag_options)
373
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
@@ -195,9 +194,9 @@ module ActiveScaffold
195
194
  def include_null_comparators?(column)
196
195
  return column.options[:null_comparators] if column.options.key? :null_comparators
197
196
  if column.association
198
- !column.association.belongs_to? || active_scaffold_config.columns[column.association.foreign_key].column.try(:null)
197
+ !column.association.belongs_to? || active_scaffold_config.columns[column.association.foreign_key].column&.null
199
198
  else
200
- column.column.try(:null)
199
+ column.column&.null
201
200
  end
202
201
  end
203
202
 
@@ -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)
@@ -225,7 +220,7 @@ module ActiveScaffold
225
220
  content_tag(
226
221
  :span,
227
222
  safe_join([' - ', send(input_method, "#{options[:name]}[to]", to_value, to_options)]),
228
- :id => "#{options[:id]}_between", :class => 'as_search_range_between', :style => (opt_value == 'BETWEEN') ? nil : 'display: none'
223
+ :id => "#{options[:id]}_between", :class => 'as_search_range_between', :style => ('display: none' unless opt_value == 'BETWEEN')
229
224
  )
230
225
  end
231
226
  content_tag :span, html, :class => 'search_range'
@@ -292,7 +287,7 @@ module ActiveScaffold
292
287
  def visibles_and_hiddens(search_config)
293
288
  visibles = []
294
289
  hiddens = []
295
- search_config.columns.each do |column|
290
+ search_config.columns.each_column do |column|
296
291
  next unless column.search_sql
297
292
  if search_config.optional_columns.include?(column.name) && !searched_by?(column)
298
293
  hiddens << column
@@ -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