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
@@ -23,6 +23,7 @@ module ActiveScaffold::DataStructures
23
23
  @active_record_class = active_record_class
24
24
  @_inheritable = []
25
25
  @set = []
26
+ @sorted = nil
26
27
 
27
28
  add(*args)
28
29
  end
@@ -48,8 +49,8 @@ module ActiveScaffold::DataStructures
48
49
  column = self[association]
49
50
  raise ArgumentError, "unknown column #{association}" if column.nil?
50
51
  raise ArgumentError, "column #{association} is not an association" if column.association.nil?
51
- raise ArugmentError, "column #{association} is not singular association" unless column.association.singular?
52
- raise ArugmentError, "column #{association} is polymorphic association" if column.association.polymorphic?
52
+ raise ArgumentError, "column #{association} is not singular association" unless column.association.singular?
53
+ raise ArgumentError, "column #{association} is polymorphic association" if column.association.polymorphic?
53
54
 
54
55
  klass = column.association.klass
55
56
  columns.each do |col|
@@ -31,7 +31,7 @@ module ActiveScaffold::DataStructures
31
31
  false
32
32
  end
33
33
 
34
- def has_many?
34
+ def has_many? # rubocop:disable Naming/PredicateName
35
35
  false
36
36
  end
37
37
 
@@ -39,7 +39,7 @@ module ActiveScaffold::DataStructures
39
39
  false
40
40
  end
41
41
 
42
- def has_one?
42
+ def has_one? # rubocop:disable Naming/PredicateName
43
43
  false
44
44
  end
45
45
 
@@ -66,6 +66,10 @@ module ActiveScaffold::DataStructures
66
66
  def sorted?(*)
67
67
  false
68
68
  end
69
+
70
+ def match_model?(model)
71
+ false
72
+ end
69
73
  end
70
74
 
71
75
  class NestedInfoAssociation < NestedInfo
@@ -74,7 +78,7 @@ module ActiveScaffold::DataStructures
74
78
  column = parent_scaffold.active_scaffold_config.columns[params[:association].to_sym]
75
79
  @param_name = column.model.name.foreign_key.to_sym
76
80
  @parent_id = params[@param_name]
77
- @association = column.try(:association)
81
+ @association = column&.association
78
82
  @child_association = association.reverse_association(model) if association
79
83
  setup_constrained_fields
80
84
  end
@@ -83,46 +87,56 @@ module ActiveScaffold::DataStructures
83
87
 
84
88
  # A through association with has_one or has_many as source association
85
89
  # create cannot be called in nested through associations, and not-nested through associations
86
- # unless create columns include through reflection of reverse association
90
+ # unless is through singular or create columns include through reflection of reverse association
87
91
  # e.g. customer -> networks -> firewall, reverse is firewall -> network -> customer,
88
92
  # firewall can be created if create columns include network
89
93
  def readonly_through_association?(columns)
90
94
  return false unless through_association?
91
- return true if association.through_reflection.options[:through]
92
- !association.source_reflection.belongs_to? && (
93
- !child_association || !columns.include?(child_association.through_reflection.name)
94
- )
95
+ return true if association.through_reflection.options[:through] # create not possible, too many levels
96
+ return true if association.source_reflection.options[:through] # create not possible, too many levels
97
+ return false if association.through_singular? # create allowed, AS has code for this
98
+
99
+ # create allowed only if through reflection in record to be created is included in create columns
100
+ !child_association || !columns.include?(child_association.through_reflection.name)
95
101
  end
96
102
 
97
103
  def through_association?
98
104
  association.through?
99
105
  end
100
106
 
107
+ def match_model?(model)
108
+ if association.polymorphic?
109
+ child_association&.inverse_klass == model
110
+ else
111
+ association.klass == model
112
+ end
113
+ end
114
+
101
115
  def sorted?(chain)
102
116
  default_sorting(chain).present?
103
117
  end
104
118
 
105
119
  def default_sorting(chain)
106
120
  return @default_sorting if defined? @default_sorting
107
- if association.scope.is_a?(Proc) && chain.respond_to?(:values) && chain.values[:order]
108
- @default_sorting = chain.values[:order]
109
- @default_sorting = @default_sorting.map(&:to_sql) if @default_sorting[0].is_a? Arel::Nodes::Node
110
- @default_sorting = @default_sorting.join(', ')
111
- end
121
+ return unless association.scope.is_a?(Proc) && chain.respond_to?(:values) && chain.values[:order]
122
+ @default_sorting = chain.values[:order]
123
+ @default_sorting = @default_sorting.map(&:to_sql) if @default_sorting[0].is_a? Arel::Nodes::Node
124
+ @default_sorting = @default_sorting.join(', ')
112
125
  end
113
126
 
114
127
  def to_params
115
- super.merge(:association => @association.name, :assoc_id => parent_id)
128
+ super.merge(:association => @association.name, @param_name => parent_id)
116
129
  end
117
130
 
118
131
  protected
119
132
 
120
133
  def setup_constrained_fields
121
- @constrained_fields = []
122
- @constrained_fields << Array(association.foreign_key).map(&:to_sym) unless association.belongs_to?
123
- if child_association && child_association != association
124
- @constrained_fields << child_association.name
125
- end
134
+ @constrained_fields = Array(association.foreign_key).map(&:to_sym) unless association.belongs_to?
135
+ @constrained_fields ||= []
136
+ return unless child_association && child_association != association
137
+
138
+ @constrained_fields << child_association.name
139
+ @constrained_fields << child_association.foreign_type.to_sym if child_association.polymorphic?
126
140
  end
127
141
  end
128
142
 
@@ -7,6 +7,10 @@ module ActiveScaffold::DataStructures
7
7
  set_values(*args)
8
8
  end
9
9
 
10
+ def initialize_dup(other)
11
+ @set = other.set.dup
12
+ end
13
+
10
14
  def set_values(*args)
11
15
  @set = []
12
16
  add(*args)
@@ -56,5 +60,9 @@ module ActiveScaffold::DataStructures
56
60
  def empty?
57
61
  @set.empty?
58
62
  end
63
+
64
+ protected
65
+
66
+ attr_reader :set
59
67
  end
60
68
  end
@@ -14,6 +14,7 @@ module ActiveScaffold::DataStructures
14
14
  @clauses = []
15
15
  @constraint_columns = []
16
16
  @model = model
17
+ @sorting_by_primary_key = false
17
18
  end
18
19
 
19
20
  def set_default_sorting
@@ -55,6 +56,9 @@ module ActiveScaffold::DataStructures
55
56
  # set({column => direction}, {column => direction})
56
57
  # set([column, direction], [column, direction])
57
58
  def set(*args)
59
+ # TODO: add deprecation unless args.size == 1 && args[0].is_a? Hash
60
+ # when deprecation is removed:
61
+ # * change list#sorting= to sorting.set(val)
58
62
  clear
59
63
  if args.first.is_a?(Enumerable)
60
64
  args.each do |h|
@@ -103,6 +107,10 @@ module ActiveScaffold::DataStructures
103
107
  @clauses.each { |clause| yield clause }
104
108
  end
105
109
 
110
+ def each_column
111
+ @clauses.each { |clause| yield clause[0] }
112
+ end
113
+
106
114
  # provides quick access to the first (and sometimes only) clause
107
115
  def first
108
116
  @clauses.first
@@ -120,7 +128,7 @@ module ActiveScaffold::DataStructures
120
128
  order = []
121
129
  each do |sort_column, sort_direction|
122
130
  next if constraint_columns.include? sort_column.name
123
- sql = grouped_columns_calculations.try(:dig, sort_column.name) || sort_column.sort[:sql]
131
+ sql = grouped_columns_calculations&.dig(sort_column.name) || sort_column.sort[:sql]
124
132
  next if sql.blank?
125
133
  sql = sql.to_sql if sql.respond_to?(:to_sql)
126
134
 
@@ -200,7 +208,7 @@ module ActiveScaffold::DataStructures
200
208
  end
201
209
 
202
210
  def postgres?
203
- model.connection.try(:adapter_name) == 'PostgreSQL'
211
+ model.connection&.adapter_name == 'PostgreSQL'
204
212
  end
205
213
 
206
214
  def setup_primary_key_order_clause
@@ -11,14 +11,25 @@ module ActiveScaffold
11
11
 
12
12
  module ClassMethods
13
13
  def active_scaffold(model_id = nil, &block)
14
- @active_scaffold_delayed = proc { super(model_id, &block) }
14
+ @delayed_monitor ||= Monitor.new
15
+ @active_scaffold_delayed = proc do
16
+ begin
17
+ @_prefixes = nil # clean prefixes in case is already cached, so our local_prefixes override is picked up
18
+ super(model_id, &block)
19
+ @active_scaffold_delayed = @delayed_monitor = nil # after configuring, no need to keep proc or monitor
20
+ rescue StandardError
21
+ # clear config variable if failed, so next request tries again
22
+ @active_scaffold_config = nil
23
+ raise
24
+ end
25
+ end
15
26
  end
16
27
 
17
28
  def config_active_scaffold_delayed
18
- return unless @active_scaffold_delayed
19
- @_prefixes = nil # clean prefixes in case is already cached, so our local_prefixes override is picked up
20
- block, @active_scaffold_delayed = @active_scaffold_delayed, nil
21
- block.call
29
+ @delayed_monitor&.synchronize do
30
+ # if called in same thread while running config, do nothing
31
+ @active_scaffold_delayed&.call unless @active_scaffold_config
32
+ end
22
33
  end
23
34
 
24
35
  def active_scaffold_config
@@ -5,9 +5,10 @@ module ActiveScaffold
5
5
  if self.class.uses_active_scaffold? && params[:adapter] && @rendering_adapter.nil? && request.xhr?
6
6
  @rendering_adapter = true # recursion control
7
7
  # if we need an adapter, then we render the actual stuff to a string and insert it into the adapter template
8
- opts = args.blank? ? {} : args.first
8
+ opts = args.any? ? args.first : {}
9
+
9
10
  render :partial => params[:adapter][1..-1],
10
- :locals => {:payload => render_to_string(opts.merge(:layout => false), &block).html_safe},
11
+ :locals => {:payload => render_to_string(opts.merge(:layout => false), &block).html_safe}, # rubocop:disable Rails/OutputSafety
11
12
  :use_full_path => true, :layout => false, :content_type => :html
12
13
  @rendering_adapter = nil # recursion control
13
14
  else
@@ -39,41 +39,33 @@ module ActiveScaffold #:nodoc:
39
39
  if args.first.is_a?(Hash) && args.first[:active_scaffold]
40
40
  render_embedded args.first
41
41
  elsif args.first == :super
42
- @_view_paths ||= lookup_context.view_paths.clone
43
- @_last_template ||= lookup_context.last_template
44
- parts = @virtual_path.split('/')
45
- template = parts.pop
46
- prefix = parts.join('/')
47
-
48
- options = args[1] || {}
49
- options[:locals] ||= {}
50
- if view_stack.last
51
- options[:locals] = view_stack.last[:locals].merge!(options[:locals]) if view_stack.last[:locals]
52
- options[:object] ||= view_stack.last[:object] if view_stack.last[:object]
53
- end
54
- options[:template] = template
55
- # if prefix is active_scaffold_overrides we must try to render with this prefix in following paths
56
- if prefix != 'active_scaffold_overrides'
57
- options[:prefixes] = lookup_context.prefixes.drop((lookup_context.prefixes.find_index(prefix) || -1) + 1)
58
- else
59
- options[:prefixes] = ['active_scaffold_overrides']
60
- last_view_path = File.expand_path(File.dirname(File.dirname(lookup_context.last_template.inspect)), Rails.root)
61
- lookup_context.view_paths = view_paths.drop(view_paths.find_index { |path| path.to_s == last_view_path } + 1)
42
+ if @lookup_context # rails 6
43
+ @_lookup_context ||= lookup_context
44
+ else # rails < 6
45
+ @_view_paths ||= lookup_context.view_paths.clone
46
+ @_last_template ||= lookup_context.last_template
62
47
  end
63
- result = super options
64
- lookup_context.view_paths = @_view_paths if @_view_paths
65
- lookup_context.last_template = @_last_template if @_last_template
48
+ result = super options_for_render_super(args[1])
49
+ @lookup_context = @_lookup_context if @_lookup_context # rails 6
50
+ lookup_context.view_paths = @_view_paths if @_view_paths # rails < 6
51
+ lookup_context.last_template = @_last_template if @_last_template # rails < 6
66
52
  result
67
53
  else
68
- @_view_paths ||= lookup_context.view_paths.clone
54
+ if @lookup_context # rails 6
55
+ @_lookup_context ||= lookup_context
56
+ else # rails < 6
57
+ @_view_paths ||= lookup_context.view_paths.clone
58
+ end
69
59
  last_template = lookup_context.last_template
70
- current_view = if args[0].is_a?(Hash)
71
- {:locals => args[0][:locals], :object => args[0][:object]}
72
- else # call is render 'partial', locals_hash
73
- {:locals => args[1]}
74
- end
60
+ current_view =
61
+ if args[0].is_a?(Hash)
62
+ {locals: args[0][:locals], object: args[0][:object]}
63
+ else # call is render 'partial', locals_hash
64
+ {locals: args[1]}
65
+ end
75
66
  view_stack << current_view if current_view
76
- lookup_context.view_paths = @_view_paths # reset view_paths in case a view render :super, and then render :partial
67
+ @lookup_context = @_lookup_context if @_lookup_context # rails 6, reset lookup_context in case a view render :super, and then render :partial
68
+ lookup_context.view_paths = @_view_paths if @_view_paths # rails < 6, reset view_paths in case a view render :super, and then render :partial
77
69
  result = super
78
70
  view_stack.pop if current_view.present?
79
71
  lookup_context.last_template = last_template
@@ -87,6 +79,46 @@ module ActiveScaffold #:nodoc:
87
79
 
88
80
  private
89
81
 
82
+ def options_for_render_super(options)
83
+ options ||= {}
84
+ options[:locals] ||= {}
85
+ if view_stack.last
86
+ options[:locals] = view_stack.last[:locals].merge!(options[:locals]) if view_stack.last[:locals]
87
+ options[:object] ||= view_stack.last[:object] if view_stack.last[:object]
88
+ end
89
+
90
+ parts = @virtual_path.split('/')
91
+ options[:template] = parts.pop
92
+ prefix = parts.join('/')
93
+ # if prefix is active_scaffold_overrides we must try to render with this prefix in following paths
94
+ if prefix != 'active_scaffold_overrides'
95
+ options[:prefixes] = lookup_context.prefixes.drop((lookup_context.prefixes.find_index(prefix) || -1) + 1)
96
+ else
97
+ options[:prefixes] = ['active_scaffold_overrides']
98
+ update_view_paths
99
+ end
100
+ options
101
+ end
102
+
103
+ def update_view_paths
104
+ last_view_path =
105
+ if @lookup_context # rails 6
106
+ File.expand_path(File.dirname(File.dirname(@lookup_context.last_template.short_identifier.to_s)), Rails.root)
107
+ else
108
+ File.expand_path(File.dirname(File.dirname(lookup_context.last_template.inspect)), Rails.root)
109
+ end
110
+ new_view_paths = view_paths.drop(view_paths.find_index { |path| path.to_s == last_view_path } + 1)
111
+ if @lookup_context # rails 6
112
+ if respond_to? :build_lookup_context # rails 6.0
113
+ build_lookup_context(new_view_paths)
114
+ else # rails 6.1
115
+ @lookup_context = ActionView::LookupContext.new(new_view_paths)
116
+ end
117
+ else
118
+ lookup_context.view_paths = new_view_paths
119
+ end
120
+ end
121
+
90
122
  def render_embedded(options)
91
123
  require 'digest/md5'
92
124
 
@@ -114,9 +146,13 @@ module ActiveScaffold #:nodoc:
114
146
  content_tag(:div, :id => id, :class => 'active-scaffold-component', :data => {:refresh => url}) do
115
147
  # parse the ActiveRecord model name from the controller path, which
116
148
  # might be a namespaced controller (e.g., 'admin/admins')
117
- model = remote_controller.to_s.sub(/.*\//, '').singularize
149
+ model = remote_controller.to_s.sub(%r{.*/}, '').singularize
118
150
  content_tag(:div, :class => 'active-scaffold-header') do
119
- content_tag :h2, link_to(options[:label] || active_scaffold_config_for(model).list.label, url, :remote => true, :class => 'load-embedded')
151
+ content_tag(:h2) do
152
+ link_label = options[:label] || active_scaffold_config_for(model).list.label
153
+ link_to(link_label, url, remote: true, class: 'load-embedded', data: {error_msg: as_(:error_500)}) <<
154
+ loading_indicator_tag(url_options)
155
+ end
120
156
  end
121
157
  end
122
158
  end
@@ -133,5 +169,30 @@ module ActionView
133
169
  Base.class_eval do
134
170
  include ActiveScaffold::RenderingHelper
135
171
  end
172
+
173
+ if Gem.loaded_specs['rails'].version.segments.first >= 6
174
+ RenderingHelper.class_eval do
175
+ # override the render method to use our @lookup_context instead of the
176
+ # memoized @_lookup_context
177
+ def render(options = {}, locals = {}, &block)
178
+ case options
179
+ when Hash
180
+ in_rendering_context(options) do |_|
181
+ # previously set view paths and lookup context are lost here
182
+ # if you use view_renderer, so instead create a new renderer
183
+ # with our context
184
+ temp_renderer = ActionView::Renderer.new(@lookup_context)
185
+ if block_given?
186
+ temp_renderer.render_partial(self, options.merge(partial: options[:layout]), &block)
187
+ else
188
+ temp_renderer.render(self, options)
189
+ end
190
+ end
191
+ else
192
+ view_renderer.render_partial(self, partial: options, locals: locals, &block)
193
+ end
194
+ end
195
+ end
196
+ end
136
197
  end
137
198
  end
@@ -0,0 +1,95 @@
1
+ require 'cow_proxy'
2
+
3
+ module CowProxy
4
+ module ActiveScaffold
5
+ module DataStructures
6
+ class Column < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::Column)
7
+ # readonly and called many times in list action
8
+ delegate :name, :cache_key, :delegated_association, :association, to: :__getobj__
9
+
10
+ def link
11
+ return @link if defined?(@link)
12
+ if __getobj__.frozen?
13
+ link_var = __getobj__.instance_variable_get(:@link)
14
+ if link_var.is_a?(Proc)
15
+ @link = link_var.call self
16
+ return @link
17
+ end
18
+ end
19
+ super
20
+ end
21
+
22
+ def sort_by(options)
23
+ @sort = options
24
+ end
25
+ end
26
+
27
+ class Set < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::Set)
28
+ protected
29
+
30
+ # Copy wrapped values to duplicated wrapped object
31
+ # @see CowProxy::Base#__copy_on_write__
32
+ # @return duplicated wrapped object
33
+ def __copy_on_write__(*)
34
+ super.tap do
35
+ new_set = __getobj__.instance_variable_get(:@set).dup
36
+ __getobj__.instance_variable_set(:@set, new_set)
37
+ end
38
+ end
39
+ end
40
+
41
+ class ActionColumns < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::ActionColumns)
42
+ def each_column(options = {})
43
+ __getobj__.each_column(options.reverse_merge(core_columns: action.core.columns)) do |column|
44
+ if column.is_a?(::ActiveScaffold::DataStructures::ActionColumns)
45
+ yield ::CowProxy.wrap(column).tap { |group| group.action = action }
46
+ else
47
+ yield column
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ class ActionLinks < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::ActionLinks)
54
+ def method_missing(name, *args, &block)
55
+ CowProxy.debug { "method missing #{name} in #{__getobj__.name}" }
56
+ return super if name =~ /[!?]$/
57
+ subgroup =
58
+ if _instance_variable_defined?("@#{name}")
59
+ _instance_variable_get("@#{name}")
60
+ else
61
+ __copy_on_write__ if __getobj__.frozen?
62
+ group = __getobj__.subgroup(name, args.first)
63
+ if group.frozen?
64
+ group = __wrap__(group)
65
+ else
66
+ CowProxy.debug { "created subgroup #{group.name}" }
67
+ end
68
+ _instance_variable_set("@#{name}", group)
69
+ end
70
+ yield subgroup if block
71
+ subgroup
72
+ end
73
+
74
+ def respond_to_missing?(name, *)
75
+ name !~ /[!?]$/
76
+ end
77
+
78
+ protected
79
+
80
+ # Copy wrapped values to duplicated wrapped object
81
+ # @see CowProxy::Base#__copy_on_write__
82
+ # @return duplicated wrapped object
83
+ def __copy_on_write__(*)
84
+ index = @parent_proxy.instance_variable_get(:@set).index(__getobj__) if @parent_proxy
85
+ super.tap do
86
+ CowProxy.debug { "replace #{index} with proxy obj in parent #{@parent_proxy.name}" } if index
87
+ @parent_proxy.instance_variable_get(:@set)[index] = self if index
88
+ new_set = __getobj__.instance_variable_get(:@set).dup
89
+ __getobj__.instance_variable_set(:@set, new_set)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end