active_scaffold 4.1.6 → 4.2.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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +27 -0
  3. data/README.md +6 -5
  4. data/app/assets/javascripts/jquery/active_scaffold.js +98 -47
  5. data/app/assets/javascripts/jquery/tiny_mce_bridge.js +15 -2
  6. data/app/assets/stylesheets/active_scaffold_images.scss +6 -0
  7. data/app/assets/stylesheets/{active_scaffold_layout.css → active_scaffold_layout.scss} +104 -4
  8. data/app/assets/stylesheets/tiny_mce_bridge.scss +11 -0
  9. data/app/views/active_scaffold_overrides/_base_form.html.erb +3 -2
  10. data/app/views/active_scaffold_overrides/_field_search.html.erb +2 -2
  11. data/app/views/active_scaffold_overrides/_form.html.erb +14 -4
  12. data/app/views/active_scaffold_overrides/_form_association.html.erb +1 -1
  13. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +5 -11
  14. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
  15. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -3
  16. data/app/views/active_scaffold_overrides/_new_record.js.erb +3 -1
  17. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +1 -1
  18. data/app/views/active_scaffold_overrides/_render_field.js.erb +67 -36
  19. data/app/views/active_scaffold_overrides/_update_field_on_create.js.erb +41 -6
  20. data/app/views/active_scaffold_overrides/action_links_menu.js.erb +1 -0
  21. data/config/locales/de.yml +9 -0
  22. data/config/locales/en.yml +11 -0
  23. data/config/locales/es.yml +8 -0
  24. data/config/locales/fr.yml +8 -0
  25. data/config/locales/hu.yml +8 -0
  26. data/config/locales/ja.yml +8 -0
  27. data/config/locales/ru.yml +8 -0
  28. data/lib/active_scaffold/actions/common_search.rb +2 -0
  29. data/lib/active_scaffold/actions/core.rb +47 -23
  30. data/lib/active_scaffold/actions/create.rb +2 -0
  31. data/lib/active_scaffold/actions/delete.rb +6 -0
  32. data/lib/active_scaffold/actions/field_search.rb +36 -11
  33. data/lib/active_scaffold/actions/list.rb +26 -8
  34. data/lib/active_scaffold/actions/mark.rb +6 -0
  35. data/lib/active_scaffold/actions/nested.rb +2 -0
  36. data/lib/active_scaffold/actions/search.rb +7 -0
  37. data/lib/active_scaffold/actions/show.rb +6 -0
  38. data/lib/active_scaffold/actions/subform.rb +2 -0
  39. data/lib/active_scaffold/actions/update.rb +8 -1
  40. data/lib/active_scaffold/active_record_permissions.rb +3 -3
  41. data/lib/active_scaffold/attribute_params.rb +35 -17
  42. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +2 -0
  43. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +10 -9
  44. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +10 -3
  45. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +2 -0
  46. data/lib/active_scaffold/bridges/active_storage.rb +2 -0
  47. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +2 -0
  48. data/lib/active_scaffold/bridges/ancestry.rb +2 -0
  49. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +2 -0
  50. data/lib/active_scaffold/bridges/bitfields/list_ui.rb +2 -0
  51. data/lib/active_scaffold/bridges/bitfields.rb +2 -0
  52. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -6
  53. data/lib/active_scaffold/bridges/cancan.rb +2 -0
  54. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +2 -0
  55. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge_helpers.rb +2 -0
  56. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +3 -1
  57. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -0
  58. data/lib/active_scaffold/bridges/carrierwave.rb +2 -0
  59. data/lib/active_scaffold/bridges/chosen/helpers.rb +13 -4
  60. data/lib/active_scaffold/bridges/chosen.rb +2 -0
  61. data/lib/active_scaffold/bridges/country_select/country_select_bridge_helper.rb +2 -0
  62. data/lib/active_scaffold/bridges/country_select.rb +2 -0
  63. data/lib/active_scaffold/bridges/date_picker/ext.rb +6 -0
  64. data/lib/active_scaffold/bridges/date_picker/helper.rb +7 -3
  65. data/lib/active_scaffold/bridges/date_picker.rb +2 -0
  66. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +2 -0
  67. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge_helpers.rb +2 -0
  68. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +3 -1
  69. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +2 -0
  70. data/lib/active_scaffold/bridges/dragonfly.rb +2 -0
  71. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +2 -0
  72. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +10 -9
  73. data/lib/active_scaffold/bridges/file_column/form_ui.rb +2 -0
  74. data/lib/active_scaffold/bridges/file_column/list_ui.rb +2 -0
  75. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +2 -0
  76. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +2 -0
  77. data/lib/active_scaffold/bridges/file_column.rb +2 -0
  78. data/lib/active_scaffold/bridges/logical_query_parser/tokens_grammar.rb +65 -0
  79. data/lib/active_scaffold/bridges/logical_query_parser/tokens_grammar.treetop +31 -0
  80. data/lib/active_scaffold/bridges/logical_query_parser.rb +9 -0
  81. data/lib/active_scaffold/bridges/paper_trail/actions.rb +2 -0
  82. data/lib/active_scaffold/bridges/paper_trail/config.rb +2 -0
  83. data/lib/active_scaffold/bridges/paper_trail/helper.rb +2 -0
  84. data/lib/active_scaffold/bridges/paper_trail/paper_trail_bridge.rb +2 -0
  85. data/lib/active_scaffold/bridges/paper_trail.rb +2 -0
  86. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +3 -1
  87. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +2 -0
  88. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +2 -0
  89. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +12 -12
  90. data/lib/active_scaffold/bridges/paperclip.rb +2 -0
  91. data/lib/active_scaffold/bridges/record_select/helpers.rb +19 -11
  92. data/lib/active_scaffold/bridges/record_select.rb +2 -0
  93. data/lib/active_scaffold/bridges/semantic_attributes/column.rb +2 -0
  94. data/lib/active_scaffold/bridges/semantic_attributes.rb +2 -0
  95. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  96. data/lib/active_scaffold/bridges/tiny_mce.rb +6 -0
  97. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +2 -0
  98. data/lib/active_scaffold/bridges/usa_state_select.rb +2 -0
  99. data/lib/active_scaffold/bridges.rb +2 -0
  100. data/lib/active_scaffold/config/base.rb +12 -7
  101. data/lib/active_scaffold/config/core.rb +26 -23
  102. data/lib/active_scaffold/config/create.rb +2 -0
  103. data/lib/active_scaffold/config/delete.rb +2 -0
  104. data/lib/active_scaffold/config/field_search.rb +2 -0
  105. data/lib/active_scaffold/config/form.rb +11 -1
  106. data/lib/active_scaffold/config/list.rb +7 -7
  107. data/lib/active_scaffold/config/mark.rb +2 -0
  108. data/lib/active_scaffold/config/nested.rb +28 -0
  109. data/lib/active_scaffold/config/search.rb +2 -0
  110. data/lib/active_scaffold/config/show.rb +2 -0
  111. data/lib/active_scaffold/config/subform.rb +2 -0
  112. data/lib/active_scaffold/config/update.rb +3 -1
  113. data/lib/active_scaffold/configurable.rb +4 -2
  114. data/lib/active_scaffold/constraints.rb +2 -0
  115. data/lib/active_scaffold/core.rb +14 -4
  116. data/lib/active_scaffold/data_structures/action_columns.rb +3 -1
  117. data/lib/active_scaffold/data_structures/action_link.rb +10 -0
  118. data/lib/active_scaffold/data_structures/action_link_separator.rb +2 -0
  119. data/lib/active_scaffold/data_structures/action_links.rb +32 -21
  120. data/lib/active_scaffold/data_structures/actions.rb +4 -2
  121. data/lib/active_scaffold/data_structures/association/abstract.rb +4 -2
  122. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +4 -2
  123. data/lib/active_scaffold/data_structures/association/active_record.rb +3 -9
  124. data/lib/active_scaffold/data_structures/association/mongoid.rb +4 -2
  125. data/lib/active_scaffold/data_structures/association.rb +2 -0
  126. data/lib/active_scaffold/data_structures/bridge.rb +3 -1
  127. data/lib/active_scaffold/data_structures/column.rb +37 -3
  128. data/lib/active_scaffold/data_structures/columns.rb +4 -2
  129. data/lib/active_scaffold/data_structures/filter.rb +3 -3
  130. data/lib/active_scaffold/data_structures/filter_option.rb +2 -0
  131. data/lib/active_scaffold/data_structures/filters.rb +3 -3
  132. data/lib/active_scaffold/data_structures/nested_info.rb +4 -2
  133. data/lib/active_scaffold/data_structures/set.rb +8 -10
  134. data/lib/active_scaffold/data_structures/sorting.rb +5 -7
  135. data/lib/active_scaffold/engine.rb +3 -4
  136. data/lib/active_scaffold/extensions/action_controller_rendering.rb +2 -0
  137. data/lib/active_scaffold/extensions/action_controller_rescueing.rb +2 -0
  138. data/lib/active_scaffold/extensions/action_view_rendering.rb +2 -0
  139. data/lib/active_scaffold/extensions/connection_adapter.rb +2 -0
  140. data/lib/active_scaffold/extensions/ice_nine.rb +2 -0
  141. data/lib/active_scaffold/extensions/localize.rb +2 -0
  142. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +2 -0
  143. data/lib/active_scaffold/extensions/paginator_extensions.rb +3 -1
  144. data/lib/active_scaffold/extensions/routing_mapper.rb +2 -0
  145. data/lib/active_scaffold/extensions/to_label.rb +2 -0
  146. data/lib/active_scaffold/extensions/unsaved_associated.rb +10 -8
  147. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -0
  148. data/lib/active_scaffold/finder.rb +57 -18
  149. data/lib/active_scaffold/helpers/action_link_helpers.rb +112 -37
  150. data/lib/active_scaffold/helpers/association_helpers.rb +4 -2
  151. data/lib/active_scaffold/helpers/controller_helpers.rb +2 -0
  152. data/lib/active_scaffold/helpers/filter_helpers.rb +11 -3
  153. data/lib/active_scaffold/helpers/form_column_helpers.rb +98 -71
  154. data/lib/active_scaffold/helpers/human_condition_helpers.rb +2 -0
  155. data/lib/active_scaffold/helpers/id_helpers.rb +2 -0
  156. data/lib/active_scaffold/helpers/list_column_helpers.rb +9 -5
  157. data/lib/active_scaffold/helpers/pagination_helpers.rb +3 -1
  158. data/lib/active_scaffold/helpers/search_column_helpers.rb +19 -9
  159. data/lib/active_scaffold/helpers/show_column_helpers.rb +4 -2
  160. data/lib/active_scaffold/helpers/tabs_helpers.rb +5 -3
  161. data/lib/active_scaffold/helpers/view_helpers.rb +3 -3
  162. data/lib/active_scaffold/marked_model.rb +6 -5
  163. data/lib/active_scaffold/orm_checks.rb +2 -0
  164. data/lib/active_scaffold/paginator.rb +4 -1
  165. data/lib/active_scaffold/registry.rb +2 -0
  166. data/lib/active_scaffold/responds_to_parent.rb +2 -0
  167. data/lib/active_scaffold/tableless.rb +23 -13
  168. data/lib/active_scaffold/version.rb +4 -2
  169. data/lib/active_scaffold.rb +10 -2
  170. data/lib/generators/active_scaffold/controller/USAGE +19 -0
  171. data/lib/generators/active_scaffold/controller/controller_generator.rb +29 -0
  172. data/lib/generators/active_scaffold/install/USAGE +2 -0
  173. data/lib/generators/active_scaffold/{install_generator.rb → install/install_generator.rb} +10 -6
  174. data/lib/generators/active_scaffold/resource/USAGE +29 -0
  175. data/lib/generators/active_scaffold/resource/resource_generator.rb +30 -0
  176. data/lib/tasks/brakeman.rake +2 -0
  177. data/shoulda_macros/macros.rb +2 -0
  178. metadata +19 -11
  179. data/lib/generators/active_scaffold/controller_generator.rb +0 -49
  180. data/lib/generators/active_scaffold/resource_generator.rb +0 -56
  181. /data/lib/generators/{templates → active_scaffold/controller/templates}/controller.rb +0 -0
  182. /data/lib/generators/{templates → active_scaffold/controller/templates}/helper.rb +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  # Helpers rendering action links
@@ -5,16 +7,16 @@ module ActiveScaffold
5
7
  # params which mustn't be copying to nested links
6
8
  NESTED_PARAMS = %i[eid embedded association parent_scaffold].freeze
7
9
 
8
- def skip_action_link?(link, *args)
9
- !link.ignore_method.nil? && controller.respond_to?(link.ignore_method, true) && controller.send(link.ignore_method, *args)
10
+ def skip_action_link?(link, *)
11
+ !link.ignore_method.nil? && controller.respond_to?(link.ignore_method, true) && controller.send(link.ignore_method, *)
10
12
  end
11
13
 
12
- def action_link_authorized?(link, *args)
14
+ def action_link_authorized?(link, *args) # rubocop:disable Naming/PredicateMethod
13
15
  auth, reason =
14
16
  if link.security_method_set? || controller.respond_to?(link.security_method, true)
15
17
  controller.send(link.security_method, *args)
16
18
  else
17
- args.empty? ? true : args.first.authorized_for?(crud_type: link.crud_type, action: link.action, reason: true)
19
+ args.empty? || args.first.authorized_for?(crud_type: link.crud_type, action: link.action, reason: true)
18
20
  end
19
21
  [auth, reason]
20
22
  end
@@ -22,6 +24,8 @@ module ActiveScaffold
22
24
  def display_dynamic_action_group(action_link, links, record_or_ul_options = nil, ul_options = nil)
23
25
  ul_options = record_or_ul_options if ul_options.nil? && record_or_ul_options.is_a?(Hash)
24
26
  record = record_or_ul_options unless record_or_ul_options.is_a?(Hash)
27
+ ul_options ||= {}
28
+ ul_options[:class] = [ul_options[:class], 'dynamic-menu'].compact.join(' ')
25
29
  html = content_tag :ul, ul_options do
26
30
  safe_join(links.map { |link| content_tag :li, link })
27
31
  end
@@ -33,7 +37,7 @@ module ActiveScaffold
33
37
  options[:options_level_0_tag] ||= nil
34
38
  options[:level] ||= 0
35
39
  options[:first_action] = true
36
- output = ActiveSupport::SafeBuffer.new
40
+ output = options.delete(:output) || ActiveSupport::SafeBuffer.new
37
41
  prev_link = separator = nil
38
42
 
39
43
  action_links.each(reverse: options.delete(:reverse), groups: true) do |link|
@@ -62,10 +66,14 @@ module ActiveScaffold
62
66
  end
63
67
 
64
68
  def display_action_link_group(link, record, options, &)
65
- options[:level] += 1
66
- content = display_action_links(link, record, options, &)
67
- options[:level] -= 1
68
- display_action_link(link, content, record, options).tap { options[:first_action] = false } if content.present?
69
+ if link.click_menu?
70
+ display_click_menu_link(link, record, options)
71
+ else
72
+ options[:level] += 1
73
+ content = display_action_links(link, record, options, &)
74
+ options[:level] -= 1
75
+ display_action_link(link, content, record, options).tap { options[:first_action] = false } if content.present?
76
+ end
69
77
  end
70
78
 
71
79
  def display_action_link_separator(options)
@@ -73,14 +81,30 @@ module ActiveScaffold
73
81
  content_tag(tag || :li, ' '.html_safe, class: 'separator')
74
82
  end
75
83
 
84
+ def display_click_menu_link(link, record, options)
85
+ action_link =
86
+ if link.path.start_with?('collection.')
87
+ ActiveScaffold::DataStructures::ActionLinks::COLLECTION_CLICK_MENU_LINK
88
+ else
89
+ ActiveScaffold::DataStructures::ActionLinks::MEMBER_CLICK_MENU_LINK
90
+ end
91
+ html = display_action_link(
92
+ action_link,
93
+ nil,
94
+ record,
95
+ options.merge(authorized: true, link: link.label(record), link_id: get_action_link_id(link, record))
96
+ )
97
+ html.gsub('--ACTION-LINKS--', ERB::Util.unwrapped_html_escape(link.path)).html_safe # rubocop:disable Rails/OutputSafety
98
+ end
99
+
76
100
  def display_action_link(link, content, record, options)
77
101
  if content
78
102
  html_classes = hover_via_click? ? 'hover_click ' : ''
79
103
  if options[:level].zero?
80
- html_classes << 'action_group'
104
+ html_classes += 'action_group'
81
105
  group_tag = :div
82
106
  else
83
- html_classes << 'top' if options[:first_action]
107
+ html_classes += 'top' if options[:first_action]
84
108
  group_tag = :li
85
109
  end
86
110
  content = content_tag(group_tag, class: html_classes.presence, onclick: ('' if hover_via_click?)) do
@@ -100,17 +124,61 @@ module ActiveScaffold
100
124
  options[:authorized] = false if link.action.nil? || link.controller.nil?
101
125
  options.delete :link if link.crud_type == :create
102
126
  end
103
- if link.action.nil? || (link.type == :member && options.key?(:authorized) && !options[:authorized])
104
- html_class = "disabled #{link.action}#{" #{link.html_options[:class]}" if link.html_options[:class].present?}"
105
- html_options = {link: action_link_text(link, record, options), class: html_class, title: options[:not_authorized_reason]}
106
- action_link_html(link, nil, html_options, record)
127
+ method =
128
+ if link.action.nil? || (link.type == :member && options.key?(:authorized) && !options[:authorized])
129
+ :render_unauthorized_action_link
130
+ else
131
+ :render_authorized_action_link
132
+ end
133
+
134
+ cache_link = cache_action_link?(link)
135
+ label = options[:link]
136
+ result = optional_cache_helper(method, link.name_to_cache.to_s, cache_link, link, record, options, cache: cache_link)
137
+ cache_link ? replace_tags_for_action_link(result, method, link, label, record, options) : result
138
+ end
139
+
140
+ def optional_cache_helper(method, key, cache, ...)
141
+ if cache
142
+ ActiveScaffold::Registry.cache(method, key) { send(method, ...) }
107
143
  else
108
- url = action_link_url(link, record)
109
- html_options = action_link_html_options(link, record, options)
110
- action_link_html(link, url, html_options, record)
144
+ send(method, ...)
111
145
  end
112
146
  end
113
147
 
148
+ def replace_tags_for_action_link(html, method, link, label, record, options) # rubocop:disable Metrics/ParameterLists
149
+ case method
150
+ when :render_unauthorized_action_link
151
+ html = html.gsub('--REASON--', ERB::Util.unwrapped_html_escape(options[:not_authorized_reason]))
152
+ when :render_authorized_action_link
153
+ html = html.gsub('--URL--', ERB::Util.unwrapped_html_escape(action_link_url(link, record)))
154
+ .gsub('--LINK_ID--', ERB::Util.unwrapped_html_escape(options[:link_id] || get_action_link_id(link, record)))
155
+ .gsub('--CONFIRM--') { ERB::Util.unwrapped_html_escape(link.confirm(h(record&.to_label))) }
156
+ .gsub('--PROMPT--') { ERB::Util.unwrapped_html_escape(link.prompt(h(record&.to_label))) }
157
+ .gsub('--ACTIVE--') { action_link_selected?(link, record) ? 'active' : '' }
158
+ end
159
+ html&.gsub('--LABEL--', h(label || link.label(record)))&.html_safe # rubocop:disable Rails/OutputSafety
160
+ end
161
+
162
+ def render_unauthorized_action_link(link, record = nil, options = {}, cache: false)
163
+ html_class = "disabled #{link.action}#{" #{link.html_options[:class]}" if link.html_options[:class].present?}"
164
+ options[:link] = '--LABEL--' if cache
165
+ html_options = {
166
+ link: action_link_text(link, record, options),
167
+ class: html_class,
168
+ title: cache ? '--REASON--' : options[:not_authorized_reason]
169
+ }
170
+ html = action_link_html(link, nil, html_options, record)
171
+ cache ? html.to_str : html
172
+ end
173
+
174
+ def render_authorized_action_link(link, record = nil, options = {}, cache: false)
175
+ url = cache ? '--URL--' : action_link_url(link, record)
176
+ options[:link] = '--LABEL--' if cache
177
+ html_options = action_link_html_options(link, record, options, cache: cache)
178
+ html = action_link_html(link, url, html_options, record)
179
+ cache ? html.to_str : html
180
+ end
181
+
114
182
  # setup the action link to inline form
115
183
  def action_link_to_inline_form(link, record)
116
184
  link = link.dup
@@ -182,6 +250,10 @@ module ActiveScaffold
182
250
  active_scaffold_config.user.cache_action_link_urls && link.type == :member && !link.dynamic_parameters.is_a?(Proc) && !sti_record?(record)
183
251
  end
184
252
 
253
+ def cache_action_link?(link)
254
+ active_scaffold_config.user.cache_action_links && link.type == :member
255
+ end
256
+
185
257
  def cached_action_link_url(link, record)
186
258
  @action_links_urls ||= {}
187
259
  @action_links_urls[link.name_to_cache.to_s] || begin
@@ -196,7 +268,7 @@ module ActiveScaffold
196
268
  end
197
269
 
198
270
  def replace_id_params_in_action_link_url(link, record, url)
199
- url = record ? url.sub('--ID--', record.to_param.to_s) : url.clone
271
+ url = record ? url.sub('--ID--', record.to_param.to_s) : url.dup
200
272
  if link.column&.association&.singular?
201
273
  child_id = record.send(link.column.association.name)&.to_param
202
274
  if child_id.present?
@@ -284,12 +356,7 @@ module ActiveScaffold
284
356
  end
285
357
 
286
358
  def cached_action_link_url_options(link, record)
287
- @action_links_url_options ||= {}
288
- @action_links_url_options[link.name_to_cache.to_s] || begin
289
- options = action_link_url_options(link, record)
290
- @action_links_url_options[link.name_to_cache.to_s] = options if cache_action_link_url_options?(link, record)
291
- options
292
- end
359
+ optional_cache_helper(:action_link_url_options, link.name_to_cache.to_s, cache_action_link_url_options?(link, record), link, record)
293
360
  end
294
361
 
295
362
  def action_link_url_options(link, record)
@@ -317,7 +384,7 @@ module ActiveScaffold
317
384
  def action_link_text(link, record, options)
318
385
  if link.image
319
386
  title = options[:link] || link.label(record)
320
- asset = (@_link_images ||= {})[link.image[:name]] ||= image_path(link.image[:name])
387
+ asset = ActiveScaffold::Registry.cache(:link_images, link.image[:name]) { image_path(link.image[:name]) }
321
388
  text = image_tag(asset, size: link.image[:size], alt: title, title: title, skip_pipeline: true)
322
389
  end
323
390
  text || options[:link]
@@ -354,8 +421,8 @@ module ActiveScaffold
354
421
  end
355
422
  end
356
423
 
357
- def action_link_html_options(link, record, options)
358
- link_id = get_action_link_id(link, record)
424
+ def action_link_html_options(link, record, options, cache: false)
425
+ link_id = cache ? '--LINK_ID--' : options[:link_id] || get_action_link_id(link, record)
359
426
  html_options = options[:html_options] || link.html_options
360
427
  html_options = html_options.merge(class: [html_options[:class], link.action.to_s].compact.join(' '))
361
428
  html_options[:link] = action_link_text(link, record, options)
@@ -365,23 +432,27 @@ module ActiveScaffold
365
432
 
366
433
  html_options[:data] ||= {}
367
434
  html_options[:data] = html_options[:data].deep_dup if html_options[:data].frozen?
368
- html_options[:data][:confirm] = link.confirm(h(record&.to_label)) if link.confirm?
435
+ html_options[:data][:confirm] = cache ? '--CONFIRM--' : link.confirm(h(record&.to_label)) if link.confirm?
369
436
  if !options[:page] && !options[:popup] && (options[:inline] || link.inline?)
370
- html_options[:class] << ' as_action'
437
+ html_options[:class] += ' as_action'
371
438
  html_options[:data][:position] = link.position if link.position
372
439
  html_options[:data][:action] = link.action
373
440
  html_options[:data][:cancel_refresh] = true if link.refresh_on_close
374
441
  html_options[:data][:keep_open] = true if link.keep_open?
375
442
  if link.prompt?
376
- html_options[:data][:prompt] = link.prompt(h(record&.to_label))
443
+ html_options[:data][:prompt] = cache ? '--PROMPT--' : link.prompt(h(record&.to_label))
377
444
  html_options[:data][:prompt_required] = true if link.prompt_required?
378
445
  end
379
446
  html_options[:remote] = true
380
447
  end
381
448
 
382
449
  if link.toggle
383
- html_options[:class] << ' toggle'
384
- html_options[:class] << ' active' if action_link_selected?(link, record)
450
+ html_options[:class] += ' toggle'
451
+ if cache
452
+ html_options[:class] << ' --ACTIVE--'
453
+ elsif action_link_selected?(link, record)
454
+ html_options[:class] << ' active'
455
+ end
385
456
  end
386
457
 
387
458
  if !options[:page] && !options[:inline] && (options[:popup] || link.popup?)
@@ -393,7 +464,7 @@ module ActiveScaffold
393
464
  end
394
465
 
395
466
  def get_action_link_id(link, record = nil)
396
- column = link.column
467
+ column = link.column unless link.is_a?(ActiveScaffold::DataStructures::ActionLinks)
397
468
  if column&.association && record
398
469
  associated = record.send(column.association.name) unless column.association.collection?
399
470
  id =
@@ -405,10 +476,14 @@ module ActiveScaffold
405
476
  end
406
477
  id ||= record&.id&.to_s || (nested? ? nested_parent_id.to_s : '')
407
478
  action_link_id = ActiveScaffold::Registry.cache :action_link_id, link.name_to_cache.to_s do
408
- if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)
409
- controller_id = id_from_controller("#{link.controller}-")
479
+ if link.is_a?(ActiveScaffold::DataStructures::ActionLinks)
480
+ action_link_id(link.path.tr('.', '_'), '--ID--')
481
+ else
482
+ if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)
483
+ controller_id = id_from_controller("#{link.controller}-")
484
+ end
485
+ action_link_id("#{controller_id}#{link.action}", '--ID--')
410
486
  end
411
- action_link_id("#{controller_id}#{link.action}", '--ID--')
412
487
  end
413
488
  action_link_id.sub('--ID--', id)
414
489
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  module AssociationHelpers
@@ -39,7 +41,7 @@ module ActiveScaffold
39
41
  include_assoc = includes_for_association(column, klass)
40
42
  relation = relation.includes(include_assoc) if include_assoc
41
43
  end
42
- if column&.sort && column.sort&.dig(:sql)
44
+ if column&.sort&.dig(:sql)
43
45
  # with threasafe enabled, column.sort[:sql] returns proxied strings and
44
46
  # regexp capture won't work, which rails uses internally, so to_s is needed
45
47
  relation = relation.order(Array(column.sort[:sql]).map { |sql| Arel.sql(sql.to_s) })
@@ -92,7 +94,7 @@ module ActiveScaffold
92
94
  def sorted_association_options_find(association, conditions = nil, record = nil)
93
95
  options = association_options_find(association, conditions, nil, record)
94
96
  column = column_for_association(association, record)
95
- unless column&.sort && column.sort&.dig(:sql)
97
+ unless column&.sort&.dig(:sql)
96
98
  method = column.options[:label_method] if column
97
99
  options = options.sort_by(&(method || :to_label).to_sym)
98
100
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  module ControllerHelpers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  # Helpers rendering filters
@@ -9,8 +11,14 @@ module ActiveScaffold
9
11
  end
10
12
 
11
13
  def display_filters(filters)
12
- content = filters.sort_by(&:weight).map { |filter| display_filter(filter) }
13
- content_tag :div, safe_join(content), class: 'filters' if content.present?
14
+ return unless filters_enabled?
15
+
16
+ content = render_filters filters
17
+ content_tag :div, content, class: 'filters' if content.present?
18
+ end
19
+
20
+ def render_filters(filters)
21
+ safe_join(filters.sort_by(&:weight).filter_map { |filter| display_filter(filter) })
14
22
  end
15
23
 
16
24
  def display_filter(filter)
@@ -29,7 +37,7 @@ module ActiveScaffold
29
37
  content = options.map do |option|
30
38
  content_tag :option, option.label(nil), data: {url: action_link_url(option, nil)}, selected: action_link_selected?(option, nil), title: option.description
31
39
  end
32
- select_tag nil, safe_join(content), class: "action_group #{link.css_class}", title: filter.description || filter.label, data: {remote: :url} if content.present?
40
+ select_tag nil, safe_join(content), class: "action_group #{filter.css_class}", title: filter.description || filter.label, data: {remote: :url} if content.present?
33
41
  end
34
42
  end
35
43
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveScaffold
2
4
  module Helpers
3
5
  # Helpers that assist with the rendering of a Form Column
@@ -23,7 +25,7 @@ module ActiveScaffold
23
25
 
24
26
  elsif column.association
25
27
  # if we get here, it's because the column has a form_ui but not one ActiveScaffold knows about.
26
- raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'" if column.form_ui
28
+ raise ArgumentError, "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'" if column.form_ui
27
29
 
28
30
  # its an association and nothing is specified, we will assume form_ui :select
29
31
  active_scaffold_input_select(column, options)
@@ -47,14 +49,15 @@ module ActiveScaffold
47
49
  text_field(:record, column.name, options.merge(column.options).except(:format))
48
50
  end
49
51
  rescue StandardError => e
50
- Rails.logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
51
- raise e
52
+ message = "on the ActiveScaffold column = :#{column.name} in #{controller.class}"
53
+ ActiveScaffold.log_exception(e, message)
54
+ raise e.class, "#{e.message} -- #{message}", e.backtrace
52
55
  end
53
56
 
54
57
  def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil) # rubocop:disable Metrics/ParameterLists
55
58
  if add_class
56
59
  col_class = []
57
- col_class << 'required' if column.required?(action_for_validation?(record))
60
+ col_class << 'required' if column.required?(action_for_validation(record))
58
61
  col_class << column.css_class unless column.css_class.nil? || column.css_class.is_a?(Proc)
59
62
  col_class << 'hidden' if column_renders_as(column) == :hidden
60
63
  col_class << 'checkbox' if column.form_ui == :checkbox
@@ -77,6 +80,18 @@ module ActiveScaffold
77
80
  }
78
81
  end
79
82
 
83
+ def active_scaffold_subform_record_actions(association_column, record, locked, scope)
84
+ return unless association_column.association.collection? && !locked
85
+
86
+ auth = %i[destroy delete_all delete].exclude?(association_column.association.dependent)
87
+ auth, reason = record.authorized_for?(crud_type: :delete, reason: true) unless auth
88
+ if auth
89
+ link_to(as_(:remove), '#', class: 'destroy')
90
+ else
91
+ content_tag :span, reason, class: 'destroy reason'
92
+ end
93
+ end
94
+
80
95
  # the standard active scaffold options used for textual inputs
81
96
  def active_scaffold_input_text_options(options = {})
82
97
  options[:autocomplete] ||= 'off'
@@ -84,7 +99,7 @@ module ActiveScaffold
84
99
  options
85
100
  end
86
101
 
87
- def action_for_validation?(record)
102
+ def action_for_validation(record)
88
103
  record&.persisted? ? :update : :create
89
104
  end
90
105
 
@@ -94,7 +109,7 @@ module ActiveScaffold
94
109
  record = options[:object]
95
110
 
96
111
  # Add some HTML5 attributes for in-browser validation and better user experience
97
- if column.required?(action_for_validation?(record)) && (!@disable_required_for_new || scope.nil? || record&.persisted?)
112
+ if column.required?(action_for_validation(record)) && (!@disable_required_for_new || scope.nil? || record&.persisted?)
98
113
  options[:required] = true
99
114
  end
100
115
  options[:placeholder] = column.placeholder if column.placeholder.present?
@@ -112,7 +127,9 @@ module ActiveScaffold
112
127
  end
113
128
 
114
129
  def current_form_columns(record, scope, subform_controller = nil)
115
- if scope
130
+ if @main_columns && (scope.nil? || subform_controller == controller.class)
131
+ @main_columns.visible_columns_names
132
+ elsif scope
116
133
  subform_controller.active_scaffold_config.subform.columns.visible_columns_names
117
134
  elsif %i[new create edit update render_field].include? action_name.to_sym
118
135
  # disable update_columns for inplace_edit (GET render_field)
@@ -122,29 +139,33 @@ module ActiveScaffold
122
139
  end
123
140
  end
124
141
 
142
+ def url_options_for_render_field(column, record, scope, subform_controller, url_params)
143
+ url_params.reverse_merge! params_for(action: 'render_field', column: column.name, id: record.to_param)
144
+ if nested? && scope
145
+ url_params[:nested] = url_params.slice(:parent_scaffold, :association, nested.param_name)
146
+ url_params = url_params.except(:parent_scaffold, :association, nested.param_name)
147
+ end
148
+ if scope
149
+ url_params[:parent_controller] ||= url_params[:controller].gsub(%r{^/}, '')
150
+ url_params[:controller] = subform_controller.controller_path
151
+ url_params[:scope] = scope
152
+ url_params[:parent_id] = params[:parent_id] || params[:id]
153
+ end
154
+ url_params
155
+ end
156
+
125
157
  def update_columns_options(column, scope, options, force = false, form_columns: nil, url_params: {})
126
158
  record = options[:object]
127
159
  subform_controller = controller.class.active_scaffold_controller_for(record.class) if scope
128
- if @main_columns && (scope.nil? || subform_controller == controller.class)
129
- form_columns ||= @main_columns.visible_columns_names
130
- end
131
160
  form_columns ||= current_form_columns(record, scope, subform_controller)
132
- if force || (form_columns && column.update_columns&.intersect?(form_columns))
133
- url_params.reverse_merge! params_for(action: 'render_field', column: column.name, id: record.to_param)
134
- if nested? && scope
135
- url_params[:nested] = url_params.slice(:parent_scaffold, :association, nested.param_name)
136
- url_params = url_params.except(:parent_scaffold, :association, nested.param_name)
137
- end
138
- if scope
139
- url_params[:parent_controller] ||= url_params[:controller].gsub(%r{^/}, '')
140
- url_params[:controller] = subform_controller.controller_path
141
- url_params[:scope] = scope
142
- url_params[:parent_id] = params[:parent_id] || params[:id]
143
- end
161
+ update_columns = column.update_columns&.flat_map { |col| col.is_a?(Hash) ? col.keys : col }
162
+ force = true if update_columns&.include?(:__root__)
144
163
 
164
+ if force || (form_columns && update_columns&.intersect?(form_columns))
165
+ url_params = url_options_for_render_field(column, record, scope, subform_controller, url_params)
145
166
  options[:class] = "#{options[:class]} update_form".strip
146
167
  options['data-update_url'] = url_for(url_params)
147
- options['data-update_send_form'] = column.send_form_on_update_column
168
+ options['data-update_send_form'] = column.update_columns&.any?(Hash) || column.send_form_on_update_column
148
169
  options['data-update_send_form_selector'] = column.options[:send_form_selector] if column.options[:send_form_selector]
149
170
  options['data-skip-disable-form'] = !column.disable_on_update_column
150
171
  end
@@ -203,13 +224,18 @@ module ActiveScaffold
203
224
  end
204
225
  end
205
226
 
227
+ def column_description(column, record, scope = nil)
228
+ desc = column.description(record, scope)
229
+ content_tag(:span, h(desc) + content_tag(:span, nil, class: 'close'), class: 'description') if desc.present?
230
+ end
231
+
206
232
  def form_attribute(column, record, scope = nil, only_value = false, col_class = nil)
207
233
  column_options = active_scaffold_input_options(column, scope, object: record)
208
234
  collapsible_id = column_options.delete :collapsible_id
209
235
  attributes = field_attributes(column, record)
210
236
  attributes[:class] = "#{attributes[:class]} #{col_class}" if col_class.present?
211
237
  if only_value
212
- field = content_tag(:span, get_column_value(record, column), column_options.except(:name, :object))
238
+ field = content_tag(:span, show_column_value(record, column), column_options.except(:name, :object))
213
239
  if column.association.nil? || column.association.belongs_to?
214
240
  # hidden field probably not needed, but leaving it just in case
215
241
  # but it isn't working for assocations which are not belongs_to
@@ -221,8 +247,8 @@ module ActiveScaffold
221
247
  end
222
248
  if field
223
249
  field << loading_indicator_tag(action: :render_field, id: params[:id]) if column.update_columns
224
- desc = column.description(record, scope)
225
- field << content_tag(:span, desc, class: 'description') if desc.present?
250
+ desc = column_description(column, record, scope)
251
+ field << desc if desc.present?
226
252
  end
227
253
 
228
254
  label = label_tag(label_for(column, column_options), form_column_label(column, record, scope))
@@ -352,7 +378,6 @@ module ActiveScaffold
352
378
  collection_select(:record, method, select_options, :id, ui_options[:label_method] || :to_label, options, html_options)
353
379
  end
354
380
  html << active_scaffold_refresh_link(column, html_options, record, ui_options) if ui_options[:refresh_link]
355
- html << active_scaffold_add_new(column, record, html_options, ui_options: ui_options) if ui_options[:add_new]
356
381
  html
357
382
  end
358
383
 
@@ -368,19 +393,7 @@ module ActiveScaffold
368
393
 
369
394
  def active_scaffold_add_new(column, record, html_options, ui_options: column.options, skip_link: false)
370
395
  options = ui_options[:add_new] == true ? {} : ui_options[:add_new]
371
- if options.is_a?(Array)
372
- ActiveScaffold.deprecator.warn "use add_new: {types: #{options.inspect}} instead of add_new: #{options.inspect}"
373
- options = {types: options}
374
- end
375
- if ui_options[:hide_subgroups] && !options.key?(:hide_subgroups)
376
- ActiveScaffold.deprecator.warn "use add_new: {hide_subgroups: #{ui_options[:hide_subgroups]}} instead of hide_subgroups: #{ui_options[:hide_subgroups]}"
377
- options[:hide_subgroups] = ui_options[:hide_subgroups]
378
- end
379
- if ui_options[:layout] && !options.key?(:layout)
380
- ActiveScaffold.deprecator.warn "use add_new: {layout: #{ui_options[:layout]}} instead of layout: #{ui_options[:layout]}"
381
- options[:layout] = ui_options[:layout]
382
- end
383
-
396
+ options[:mode] = :popup if column.association&.collection?
384
397
  case options[:mode]
385
398
  when nil, :subform
386
399
  active_scaffold_new_record_subform(column, record, html_options, options: options, skip_link: skip_link)
@@ -461,31 +474,32 @@ module ActiveScaffold
461
474
  link_to(label, '#', data: data, class: 'show-new-subform')
462
475
  end
463
476
 
464
- def active_scaffold_file_with_remove_link(column, options, content, remove_file_prefix, controls_class, ui_options: column.options, &block)
477
+ def active_scaffold_file_with_content(column, options, content, remove_file_prefix, controls_class, ui_options: column.options)
465
478
  options = active_scaffold_input_text_options(options.merge(ui_options))
479
+ options[:style] = 'display: none' if content
480
+ field = file_field(:record, column.name, options)
481
+
466
482
  if content
467
- active_scaffold_file_with_content(column, content, options, remove_file_prefix, controls_class, &block)
483
+ content = [content, ' | ']
484
+ content << yield if block_given?
485
+ object_name, method = options[:name].split(/\[(#{column.name})\]/)
486
+ method.sub!(/#{column.name}/, "#{remove_file_prefix}\\0")
487
+ content << hidden_field(object_name, method, value: 'false', class: 'remove_file')
488
+ active_scaffold_file_with_remove_link(safe_join(content), options, controls_class) { field }
468
489
  else
469
- file_field(:record, column.name, options)
490
+ field
470
491
  end
471
492
  end
472
493
 
473
- def active_scaffold_file_with_content(column, content, options, remove_file_prefix, controls_class)
494
+ def active_scaffold_file_with_remove_link(content, options, controls_class, link_key = nil)
474
495
  required = options.delete(:required)
475
- js_remove_file_code = "jQuery(this).prev().val('true'); jQuery(this).parent().hide().next().show()#{".find('input').attr('required', 'required')" if required}; return false;"
476
- js_dont_remove_file_code = "jQuery(this).parents('div.#{controls_class}').find('input.remove_file').val('false'); return false;"
477
-
478
- object_name, method = options[:name].split(/\[(#{column.name})\]/)
479
- method.sub!(/#{column.name}/, "#{remove_file_prefix}\\0")
480
- fields = block_given? ? yield : ''
481
- link_key = options[:multiple] ? :remove_files : :remove_file
482
- input = file_field(:record, column.name, options.merge(onchange: js_dont_remove_file_code))
483
- content_tag(:div, class: controls_class) do
484
- content_tag(:div) do
485
- safe_join [content, ' | ', fields,
486
- hidden_field(object_name, method, value: 'false', class: 'remove_file'),
487
- content_tag(:a, as_(link_key), href: '#', onclick: js_remove_file_code)]
488
- end << content_tag(:div, input, style: 'display: none')
496
+ link_key ||= options[:multiple] ? :remove_files : :remove_file
497
+ content_tag(:div, class: "#{controls_class} file-input-controls", data: {required: required}) do
498
+ content_line = content_tag(:div) do
499
+ safe_join [content, content_tag(:a, as_(link_key), href: '#', class: 'remove-file-btn')]
500
+ end
501
+ content_line << yield if block_given?
502
+ content_line
489
503
  end
490
504
  end
491
505
 
@@ -533,7 +547,7 @@ module ActiveScaffold
533
547
  end
534
548
 
535
549
  def active_scaffold_input_draggable(column, options, ui_options: column.options)
536
- active_scaffold_input_plural_association(column, options.merge(draggable_lists: true), ui_options: ui_options)
550
+ active_scaffold_input_select(column, options.merge(draggable_lists: true), ui_options: ui_options)
537
551
  end
538
552
 
539
553
  def active_scaffold_checkbox_option(option, label_method, associated_ids, checkbox_options, li_options = {})
@@ -594,13 +608,20 @@ module ActiveScaffold
594
608
  end
595
609
 
596
610
  def active_scaffold_input_select(column, html_options, ui_options: column.options)
597
- if column.association&.singular?
598
- active_scaffold_input_singular_association(column, html_options, ui_options: ui_options)
599
- elsif column.association&.collection?
600
- active_scaffold_input_plural_association(column, html_options, ui_options: ui_options)
601
- else
602
- active_scaffold_input_enum(column, html_options, ui_options: ui_options)
611
+ record = html_options[:object]
612
+ html =
613
+ if column.association&.singular?
614
+ active_scaffold_input_singular_association(column, html_options, ui_options: ui_options)
615
+ elsif column.association&.collection?
616
+ active_scaffold_input_plural_association(column, html_options, ui_options: ui_options)
617
+ else
618
+ active_scaffold_input_enum(column, html_options, ui_options: ui_options)
619
+ end
620
+ if ui_options[:add_new]
621
+ html = content_tag(:div, html, class: 'select-field') <<
622
+ active_scaffold_add_new(column, record, html_options, ui_options: ui_options)
603
623
  end
624
+ html
604
625
  end
605
626
 
606
627
  def active_scaffold_input_select_multiple(column, options, ui_options: column.options)
@@ -639,8 +660,11 @@ module ActiveScaffold
639
660
  selected_id = selected&.id
640
661
  if options.present?
641
662
  if ui_options[:add_new]
642
- html_options[:data] ||= {}
643
- html_options[:data][:subform_id] = active_scaffold_subform_attributes(column, ui_options: ui_options)[:id]
663
+ add_new_subform = ui_options[:add_new] == true || ui_options[:add_new][:mode].in?([nil, :subform])
664
+ if add_new_subform
665
+ html_options[:data] ||= {}
666
+ html_options[:data][:subform_id] = active_scaffold_subform_attributes(column, ui_options: ui_options)[:id]
667
+ end
644
668
  radio_html_options = html_options.merge(class: "#{html_options[:class]} hide-new-subform")
645
669
  else
646
670
  radio_html_options = html_options
@@ -655,7 +679,7 @@ module ActiveScaffold
655
679
  radios.prepend content_tag(:label, radio_button(:record, column.name, '', html_options.merge(id: radio_id)) + label)
656
680
  end
657
681
  if ui_options[:add_new]
658
- if ui_options[:add_new] == true || ui_options[:add_new][:mode].in?([nil, :subform])
682
+ if add_new_subform
659
683
  create_new = content_tag(:label) do
660
684
  radio_button_tag(html_options[:name], '', selected&.new_record?, html_options.merge(
661
685
  id: "#{html_options[:id]}-create_new", class: "#{html_options[:class]} show-new-subform"
@@ -679,7 +703,10 @@ module ActiveScaffold
679
703
  else
680
704
  html = content_tag(:span, as_(:no_options), class: "#{html_options[:class]} no-options", id: html_options[:id])
681
705
  html << hidden_field_tag(html_options[:name], '', id: nil)
682
- html << active_scaffold_add_new(column, record, html_options, ui_options: ui_options) if ui_options[:add_new]
706
+ if ui_options[:add_new]
707
+ html = content_tag(:div, html, class: 'select-field') <<
708
+ active_scaffold_add_new(column, record, html_options, ui_options: ui_options)
709
+ end
683
710
  html
684
711
  end
685
712
  end
@@ -851,9 +878,9 @@ module ActiveScaffold
851
878
  end
852
879
  end
853
880
 
854
- def column_scope(column, scope = nil, record = nil)
881
+ def column_scope(column, scope = nil, record = nil, generated_id = nil)
855
882
  if column.association&.collection?
856
- "#{scope}[#{column.name}][#{record.id || generate_temporary_id(record)}]"
883
+ "#{scope}[#{column.name}][#{record.id || generate_temporary_id(record, generated_id)}]"
857
884
  else
858
885
  "#{scope}[#{column.name}]"
859
886
  end