active_scaffold 3.5.4 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +72 -0
  3. data/README.md +20 -8
  4. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  5. data/app/assets/javascripts/jquery/active_scaffold.js +98 -7
  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.html.erb +2 -1
  11. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +3 -2
  12. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +9 -7
  13. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +4 -4
  14. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +2 -1
  15. data/app/views/active_scaffold_overrides/_list.html.erb +2 -1
  16. data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
  17. data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -0
  18. data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
  19. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  20. data/app/views/active_scaffold_overrides/_messages.html.erb +1 -0
  21. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  22. data/app/views/active_scaffold_overrides/_render_field.js.erb +2 -1
  23. data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -1
  24. data/app/views/active_scaffold_overrides/_show_columns.html.erb +2 -2
  25. data/app/views/active_scaffold_overrides/_show_horizontal_record.html.erb +4 -4
  26. data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -1
  27. data/app/views/active_scaffold_overrides/_update_column.js.erb +2 -2
  28. data/app/views/active_scaffold_overrides/_vertical_subform.html.erb +2 -2
  29. data/app/views/active_scaffold_overrides/action_confirmation.html.erb +2 -2
  30. data/app/views/active_scaffold_overrides/delete.html.erb +2 -2
  31. data/app/views/active_scaffold_overrides/on_action_update.js.erb +16 -6
  32. data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
  33. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  34. data/app/views/active_scaffold_overrides/update_column.js.erb +2 -2
  35. data/config/locales/de.yml +2 -1
  36. data/config/locales/en.yml +1 -0
  37. data/config/locales/es.yml +1 -0
  38. data/config/locales/fr.yml +2 -1
  39. data/config/locales/hu.yml +1 -0
  40. data/config/locales/ja.yml +1 -0
  41. data/config/locales/ru.yml +1 -0
  42. data/lib/active_scaffold.rb +19 -16
  43. data/lib/active_scaffold/actions/common_search.rb +11 -8
  44. data/lib/active_scaffold/actions/core.rb +91 -70
  45. data/lib/active_scaffold/actions/create.rb +28 -28
  46. data/lib/active_scaffold/actions/delete.rb +3 -3
  47. data/lib/active_scaffold/actions/field_search.rb +53 -43
  48. data/lib/active_scaffold/actions/list.rb +111 -27
  49. data/lib/active_scaffold/actions/nested.rb +65 -48
  50. data/lib/active_scaffold/actions/search.rb +1 -1
  51. data/lib/active_scaffold/actions/show.rb +4 -4
  52. data/lib/active_scaffold/actions/subform.rb +23 -22
  53. data/lib/active_scaffold/actions/update.rb +96 -77
  54. data/lib/active_scaffold/active_record_permissions.rb +2 -11
  55. data/lib/active_scaffold/attribute_params.rb +102 -94
  56. data/lib/active_scaffold/bridges.rb +8 -8
  57. data/lib/active_scaffold/bridges/active_storage.rb +6 -0
  58. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +34 -0
  59. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
  60. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
  61. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
  62. data/lib/active_scaffold/bridges/bitfields.rb +2 -1
  63. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  64. data/lib/active_scaffold/bridges/bitfields/list_ui.rb +19 -0
  65. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
  66. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -12
  67. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
  68. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  69. data/lib/active_scaffold/bridges/chosen/helpers.rb +7 -6
  70. data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
  71. data/lib/active_scaffold/bridges/date_picker/helper.rb +49 -44
  72. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  73. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  74. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
  75. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  76. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +10 -7
  77. data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
  78. data/lib/active_scaffold/bridges/paper_trail/actions.rb +3 -1
  79. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  80. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
  81. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  82. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -17
  83. data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -19
  84. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  85. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +21 -4
  86. data/lib/active_scaffold/config/base.rb +133 -41
  87. data/lib/active_scaffold/config/core.rb +146 -18
  88. data/lib/active_scaffold/config/delete.rb +14 -1
  89. data/lib/active_scaffold/config/field_search.rb +7 -1
  90. data/lib/active_scaffold/config/form.rb +10 -1
  91. data/lib/active_scaffold/config/list.rb +39 -13
  92. data/lib/active_scaffold/config/mark.rb +4 -2
  93. data/lib/active_scaffold/config/nested.rb +16 -17
  94. data/lib/active_scaffold/config/search.rb +9 -0
  95. data/lib/active_scaffold/config/show.rb +4 -0
  96. data/lib/active_scaffold/config/update.rb +4 -0
  97. data/lib/active_scaffold/configurable.rb +14 -7
  98. data/lib/active_scaffold/constraints.rb +22 -20
  99. data/lib/active_scaffold/core.rb +67 -28
  100. data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
  101. data/lib/active_scaffold/data_structures/action_link.rb +50 -20
  102. data/lib/active_scaffold/data_structures/action_links.rb +15 -13
  103. data/lib/active_scaffold/data_structures/association/abstract.rb +38 -15
  104. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  105. data/lib/active_scaffold/data_structures/association/active_record.rb +6 -2
  106. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  107. data/lib/active_scaffold/data_structures/column.rb +75 -66
  108. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  109. data/lib/active_scaffold/data_structures/nested_info.rb +33 -19
  110. data/lib/active_scaffold/data_structures/set.rb +8 -0
  111. data/lib/active_scaffold/data_structures/sorting.rb +10 -2
  112. data/lib/active_scaffold/delayed_setup.rb +16 -5
  113. data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -2
  114. data/lib/active_scaffold/extensions/action_view_rendering.rb +93 -32
  115. data/lib/active_scaffold/extensions/cow_proxy.rb +95 -0
  116. data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
  117. data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
  118. data/lib/active_scaffold/extensions/localize.rb +3 -1
  119. data/lib/active_scaffold/extensions/routing_mapper.rb +6 -45
  120. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  121. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
  122. data/lib/active_scaffold/finder.rb +110 -77
  123. data/lib/active_scaffold/helpers/action_link_helpers.rb +62 -36
  124. data/lib/active_scaffold/helpers/association_helpers.rb +18 -16
  125. data/lib/active_scaffold/helpers/controller_helpers.rb +34 -10
  126. data/lib/active_scaffold/helpers/form_column_helpers.rb +196 -124
  127. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  128. data/lib/active_scaffold/helpers/id_helpers.rb +6 -2
  129. data/lib/active_scaffold/helpers/list_column_helpers.rb +90 -57
  130. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  131. data/lib/active_scaffold/helpers/search_column_helpers.rb +29 -34
  132. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  133. data/lib/active_scaffold/helpers/view_helpers.rb +39 -36
  134. data/lib/active_scaffold/marked_model.rb +2 -2
  135. data/lib/active_scaffold/orm_checks.rb +3 -7
  136. data/lib/active_scaffold/paginator.rb +7 -7
  137. data/lib/active_scaffold/registry.rb +33 -0
  138. data/lib/active_scaffold/responds_to_parent.rb +8 -11
  139. data/lib/active_scaffold/tableless.rb +82 -66
  140. data/lib/active_scaffold/version.rb +2 -2
  141. data/lib/generators/active_scaffold/controller_generator.rb +2 -2
  142. data/lib/generators/active_scaffold/install_generator.rb +52 -4
  143. data/lib/generators/active_scaffold/resource_generator.rb +2 -2
  144. data/shoulda_macros/macros.rb +3 -1
  145. data/test/bridges/date_picker_test.rb +1 -2
  146. data/test/bridges/paperclip_test.rb +6 -6
  147. data/test/class_with_finder.rb +2 -2
  148. data/test/company.rb +4 -4
  149. data/test/config/create_test.rb +4 -2
  150. data/test/config/nested_test.rb +1 -1
  151. data/test/config/show_test.rb +1 -1
  152. data/test/config/update_test.rb +7 -6
  153. data/test/data_structures/action_columns_test.rb +2 -2
  154. data/test/data_structures/action_links_test.rb +1 -1
  155. data/test/data_structures/column_test.rb +3 -6
  156. data/test/data_structures/columns_test.rb +2 -2
  157. data/test/data_structures/sorting_test.rb +7 -0
  158. data/test/extensions/action_view_rendering_test.rb +20 -0
  159. data/test/extensions/active_record_test.rb +4 -4
  160. data/test/extensions/routing_mapper_test.rb +2 -2
  161. data/test/helpers/list_column_helpers_test.rb +3 -1
  162. data/test/misc/active_record_permissions_test.rb +3 -11
  163. data/test/misc/attribute_params_test.rb +12 -8
  164. data/test/misc/calculation_test.rb +1 -1
  165. data/test/misc/configurable_test.rb +10 -10
  166. data/test/misc/constraints_test.rb +2 -2
  167. data/test/misc/convert_numbers_format_test.rb +7 -3
  168. data/test/misc/lang_test.rb +1 -1
  169. data/test/misc/parse_datetime_test.rb +3 -4
  170. data/test/misc/tableless_test.rb +14 -0
  171. data/test/mock_app/Rakefile +1 -1
  172. data/test/mock_app/app/assets/config/manifest.js +0 -0
  173. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  174. data/test/mock_app/app/controllers/people_controller.rb +5 -1
  175. data/test/mock_app/app/controllers/roles_controller.rb +4 -0
  176. data/test/mock_app/app/views/active_scaffold_overrides/_form.html.erb +2 -0
  177. data/test/mock_app/app/views/active_scaffold_overrides/list.html.erb +2 -0
  178. data/test/mock_app/app/views/people/_first_name_form_column.html.erb +2 -0
  179. data/test/mock_app/app/views/people/_form.html.erb +2 -0
  180. data/test/mock_app/app/views/people/list.html.erb +2 -0
  181. data/test/mock_app/config/application.rb +2 -1
  182. data/test/mock_app/config/boot.rb +1 -1
  183. data/test/mock_app/config/environment.rb +2 -2
  184. data/test/mock_app/config/routes.rb +4 -1
  185. data/test/mock_app/db/schema.rb +2 -0
  186. data/test/performance/list_cars_performance_test.rb +34 -0
  187. data/test/performance/list_people_performance_test.rb +31 -0
  188. data/test/performance_test_help.rb +3 -0
  189. data/test/test_helper.rb +12 -4
  190. metadata +69 -18
  191. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  192. 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,31 @@ 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
+ if cached_counts
174
+ key = column.association.primary_key if count_on_association_class?(column)
175
+ cached_counts[record.send(key || :id)] || 0
176
+ else
177
+ value.size
178
+ end
179
+ end
180
+
165
181
  def format_number_value(value, options = {})
166
182
  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
183
+ value =
184
+ case options[:format]
185
+ when :size
186
+ number_to_human_size(value, options[:i18n_options] || {})
187
+ when :percentage
188
+ number_to_percentage(value, options[:i18n_options] || {})
189
+ when :currency
190
+ number_to_currency(value, options[:i18n_options] || {})
191
+ when :i18n_number
192
+ send("number_with_#{value.is_a?(Integer) ? 'delimiter' : 'precision'}", value, options[:i18n_options] || {})
193
+ else
194
+ value
195
+ end
179
196
  end
180
197
  clean_column_value(value)
181
198
  end
@@ -196,18 +213,26 @@ module ActiveScaffold
196
213
  end
197
214
  end
198
215
 
216
+ def association_join_text(column = nil)
217
+ column_value = column&.association_join_text
218
+ return column_value if column_value
219
+ return @_association_join_text if defined? @_association_join_text
220
+ @_association_join_text = active_scaffold_config.list.association_join_text
221
+ end
222
+
199
223
  def format_collection_association_value(value, column, label_method, size)
200
- if column.associated_limit.nil?
224
+ associated_limit = column.associated_limit
225
+ if associated_limit.nil?
201
226
  firsts = value.collect(&label_method)
202
- safe_join firsts, active_scaffold_config.list.association_join_text
203
- elsif column.associated_limit.zero?
227
+ safe_join firsts, association_join_text(column)
228
+ elsif associated_limit.zero?
204
229
  size if column.associated_number?
205
230
  else
206
- firsts = value.loaded? ? value[0, column.associated_limit] : value.limit(column.associated_limit)
231
+ firsts = value.loaded? ? value[0, associated_limit] : value.limit(associated_limit)
207
232
  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
233
+ firsts << '…' if value.size > associated_limit
234
+ text = safe_join firsts, association_join_text(column)
235
+ text << " (#{size})" if column.associated_number? && associated_limit && value.size > associated_limit
211
236
  text
212
237
  end
213
238
  end
@@ -237,7 +262,7 @@ module ActiveScaffold
237
262
  empty_field_text
238
263
  elsif column_value.is_a?(Time) || column_value.is_a?(Date)
239
264
  l(column_value, :format => options[:format] || :default)
240
- elsif [FalseClass, TrueClass].include?(column_value.class)
265
+ elsif !!column_value == column_value # rubocop:disable Style/DoubleNegation fast check for boolean
241
266
  as_(column_value.to_s.to_sym)
242
267
  else
243
268
  column_value.to_s
@@ -246,15 +271,21 @@ module ActiveScaffold
246
271
  end
247
272
 
248
273
  def cache_association(association, column, size)
274
+ associated_limit = column.associated_limit
249
275
  # 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?
276
+ if associated_limit.nil?
251
277
  logger.warn "ActiveScaffold: Enable eager loading for #{column.name} association to reduce SQL queries"
252
- elsif column.associated_limit > 0
278
+ elsif associated_limit.positive?
253
279
  # 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
280
+ association.target = association.reader.limit(associated_limit + 1).select(column.select_associated_columns || "#{association.klass.quoted_table_name}.*").to_a
255
281
  elsif @cache_associations
256
282
  # 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]
283
+ association.target =
284
+ if size.to_i.zero?
285
+ []
286
+ else
287
+ ActiveScaffold::Registry.cache(:cached_empty_association, association.klass) { [association.klass.new] }
288
+ end
258
289
  end
259
290
  end
260
291
 
@@ -265,14 +296,9 @@ module ActiveScaffold
265
296
  def inplace_edit?(record, column)
266
297
  return unless column.inplace_edit
267
298
  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
299
+ return Array(controller.send(:update_authorized?, record, column.name))[0]
274
300
  end
275
- editable || record.authorized_for?(:crud_type => :update, :column => column.name)
301
+ record.authorized_for?(:crud_type => :update, :column => column.name)
276
302
  end
277
303
 
278
304
  def inplace_edit_cloning?(column)
@@ -280,23 +306,29 @@ module ActiveScaffold
280
306
  end
281
307
 
282
308
  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}}
309
+ @_inplace_edit_title ||= as_(:click_to_edit)
310
+ cell_id = ActiveScaffold::Registry.cache :inplace_edit_id, column.cache_key do
311
+ element_cell_id(id: '--ID--', action: 'update_column', name: column.name.to_s)
312
+ end
313
+ tag_options = {id: cell_id.sub('--ID--', record.id.to_s), class: 'in_place_editor_field',
314
+ title: @_inplace_edit_title, data: {:ie_id => record.to_param}}
286
315
  tag_options[:data][:ie_update] = column.inplace_edit if column.inplace_edit != true
287
316
  tag_options
288
317
  end
289
318
 
290
319
  def active_scaffold_inplace_edit(record, column, options = {})
291
320
  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))
321
+ @_inplace_edit_handle ||= content_tag(:span, as_(:inplace_edit_handle), :class => 'handle')
322
+ span = content_tag(:span, formatted_column, active_scaffold_inplace_edit_tag_options(record, column))
323
+ @_inplace_edit_handle + span
294
324
  end
295
325
 
296
326
  def inplace_edit_control(column)
297
327
  return unless inplace_edit?(active_scaffold_config.model, column) && inplace_edit_cloning?(column)
298
- column = column.clone
299
- column.options = column.options.clone
328
+ unless ActiveScaffold.threadsafe
329
+ column = column.dup
330
+ column.options = column.options.dup
331
+ end
300
332
  column.form_ui = :select if column.association && column.form_ui.nil?
301
333
  options = active_scaffold_input_options(column).merge(:object => column.active_record_class.new)
302
334
  options[:class] = "#{options[:class]} inplace_field"
@@ -309,6 +341,7 @@ module ActiveScaffold
309
341
  'as_inplace_pattern'
310
342
  end
311
343
 
344
+ INPLACE_EDIT_PLURAL_FORM_UI = %i[select record_select].freeze
312
345
  def inplace_edit_data(column)
313
346
  data = {}
314
347
  data[:ie_url] = url_for(params_for(:action => 'update_column', :column => column.name, :id => '__id__'))
@@ -316,7 +349,7 @@ module ActiveScaffold
316
349
  data[:ie_loading_text] = column.options[:loading_text] || as_(:loading)
317
350
  data[:ie_save_text] = column.options[:save_text] || as_(:update)
318
351
  data[:ie_saving_text] = column.options[:saving_text] || as_(:saving)
319
- data[:ie_rows] = column.options[:rows] || 5 if column.column.try(:type) == :text
352
+ data[:ie_rows] = column.options[:rows] || 5 if column.column&.type == :text
320
353
  data[:ie_cols] = column.options[:cols] if column.options[:cols]
321
354
  data[:ie_size] = column.options[:size] if column.options[:size]
322
355
  data[:ie_use_html] = column.options[:use_html] if column.options[:use_html]
@@ -327,7 +360,7 @@ module ActiveScaffold
327
360
  data[:ie_mode] = :clone
328
361
  elsif column.inplace_edit == :ajax
329
362
  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)
363
+ plural = column.association&.collection? && !override_form_field?(column) && INPLACE_EDIT_PLURAL_FORM_UI.include?(column.form_ui)
331
364
  data[:ie_render_url] = url
332
365
  data[:ie_mode] = :ajax
333
366
  data[:ie_plural] = plural
@@ -366,8 +399,8 @@ module ActiveScaffold
366
399
  :ie_mode => :inline_checkbox,
367
400
  :ie_url => url_for(params_for(:action => 'mark', :id => '__id__'))
368
401
  }
369
- else
370
- tag_options[:data] = inplace_edit_data(column) if column.inplace_edit
402
+ elsif column.inplace_edit
403
+ tag_options[:data] = inplace_edit_data(column)
371
404
  end
372
405
  content_tag(:th, column_heading_value(column, sorting, sort_direction) + inplace_edit_control(column), tag_options)
373
406
  end
@@ -398,16 +431,16 @@ module ActiveScaffold
398
431
 
399
432
  # CALCULATIONS
400
433
 
401
- def column_calculation(column)
434
+ def column_calculation(column, id_condition: true)
402
435
  if column.calculate.instance_of? Proc
403
436
  column.calculate.call(@records)
404
437
  else
405
- calculate_query.calculate(column.calculate, column.name)
438
+ calculate_query(id_condition).calculate(column.calculate, column.name)
406
439
  end
407
440
  end
408
441
 
409
- def render_column_calculation(column)
410
- calculation = column_calculation(column)
442
+ def render_column_calculation(column, id_condition: true)
443
+ calculation = column_calculation(column, id_condition: id_condition)
411
444
  override_formatter = "render_#{column.name}_#{column.calculate.is_a?(Proc) ? :calculate : column.calculate}"
412
445
  calculation = send(override_formatter, calculation) if respond_to? override_formatter
413
446
  format_column_calculation(column, calculation)
@@ -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