active_scaffold 3.5.4 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
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