active_scaffold 3.6.0.pre → 3.6.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +39 -0
  3. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  4. data/app/assets/javascripts/jquery/active_scaffold.js +35 -4
  5. data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
  6. data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
  7. data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
  8. data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
  9. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  11. data/config/locales/de.yml +2 -1
  12. data/config/locales/en.yml +1 -0
  13. data/config/locales/es.yml +1 -0
  14. data/config/locales/fr.yml +2 -1
  15. data/config/locales/hu.yml +1 -0
  16. data/config/locales/ja.yml +1 -0
  17. data/config/locales/ru.yml +1 -0
  18. data/lib/active_scaffold.rb +8 -3
  19. data/lib/active_scaffold/actions/common_search.rb +11 -8
  20. data/lib/active_scaffold/actions/core.rb +79 -51
  21. data/lib/active_scaffold/actions/create.rb +27 -27
  22. data/lib/active_scaffold/actions/delete.rb +1 -1
  23. data/lib/active_scaffold/actions/field_search.rb +52 -42
  24. data/lib/active_scaffold/actions/list.rb +106 -23
  25. data/lib/active_scaffold/actions/nested.rb +59 -42
  26. data/lib/active_scaffold/actions/show.rb +3 -3
  27. data/lib/active_scaffold/actions/subform.rb +9 -16
  28. data/lib/active_scaffold/actions/update.rb +95 -77
  29. data/lib/active_scaffold/attribute_params.rb +93 -68
  30. data/lib/active_scaffold/bridges/active_storage.rb +6 -0
  31. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
  32. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
  33. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
  34. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
  35. data/lib/active_scaffold/bridges/bitfields.rb +1 -0
  36. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  37. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +6 -0
  38. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  39. data/lib/active_scaffold/bridges/date_picker/helper.rb +46 -41
  40. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  41. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +2 -2
  42. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  43. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +3 -1
  44. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  45. data/lib/active_scaffold/bridges/record_select/helpers.rb +3 -7
  46. data/lib/active_scaffold/bridges/shared/date_bridge.rb +19 -18
  47. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  48. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +20 -3
  49. data/lib/active_scaffold/config/base.rb +58 -34
  50. data/lib/active_scaffold/config/core.rb +31 -12
  51. data/lib/active_scaffold/config/delete.rb +12 -1
  52. data/lib/active_scaffold/config/list.rb +17 -7
  53. data/lib/active_scaffold/config/mark.rb +1 -1
  54. data/lib/active_scaffold/configurable.rb +5 -3
  55. data/lib/active_scaffold/constraints.rb +21 -19
  56. data/lib/active_scaffold/core.rb +35 -26
  57. data/lib/active_scaffold/data_structures/action_columns.rb +1 -1
  58. data/lib/active_scaffold/data_structures/action_link.rb +34 -16
  59. data/lib/active_scaffold/data_structures/action_links.rb +9 -11
  60. data/lib/active_scaffold/data_structures/association/abstract.rb +35 -13
  61. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  62. data/lib/active_scaffold/data_structures/association/active_record.rb +5 -1
  63. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  64. data/lib/active_scaffold/data_structures/column.rb +49 -58
  65. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  66. data/lib/active_scaffold/data_structures/nested_info.rb +20 -18
  67. data/lib/active_scaffold/data_structures/sorting.rb +5 -0
  68. data/lib/active_scaffold/delayed_setup.rb +16 -6
  69. data/lib/active_scaffold/extensions/action_controller_rendering.rb +1 -1
  70. data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
  71. data/lib/active_scaffold/extensions/cow_proxy.rb +50 -2
  72. data/lib/active_scaffold/extensions/localize.rb +3 -1
  73. data/lib/active_scaffold/extensions/routing_mapper.rb +2 -2
  74. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  75. data/lib/active_scaffold/finder.rb +81 -46
  76. data/lib/active_scaffold/helpers/action_link_helpers.rb +47 -21
  77. data/lib/active_scaffold/helpers/association_helpers.rb +13 -11
  78. data/lib/active_scaffold/helpers/controller_helpers.rb +14 -11
  79. data/lib/active_scaffold/helpers/form_column_helpers.rb +133 -99
  80. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  81. data/lib/active_scaffold/helpers/id_helpers.rb +4 -0
  82. data/lib/active_scaffold/helpers/list_column_helpers.rb +76 -49
  83. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  84. data/lib/active_scaffold/helpers/search_column_helpers.rb +25 -30
  85. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  86. data/lib/active_scaffold/helpers/view_helpers.rb +31 -22
  87. data/lib/active_scaffold/orm_checks.rb +2 -2
  88. data/lib/active_scaffold/paginator.rb +1 -3
  89. data/lib/active_scaffold/registry.rb +11 -0
  90. data/lib/active_scaffold/responds_to_parent.rb +6 -5
  91. data/lib/active_scaffold/tableless.rb +6 -8
  92. data/lib/active_scaffold/version.rb +1 -1
  93. data/shoulda_macros/macros.rb +3 -1
  94. data/test/bridges/paperclip_test.rb +1 -1
  95. data/test/company.rb +2 -2
  96. data/test/data_structures/action_columns_test.rb +2 -2
  97. data/test/data_structures/column_test.rb +3 -6
  98. data/test/data_structures/columns_test.rb +2 -2
  99. data/test/extensions/active_record_test.rb +4 -4
  100. data/test/extensions/routing_mapper_test.rb +2 -2
  101. data/test/helpers/list_column_helpers_test.rb +3 -1
  102. data/test/misc/active_record_permissions_test.rb +2 -2
  103. data/test/misc/attribute_params_test.rb +4 -0
  104. data/test/misc/configurable_test.rb +10 -10
  105. data/test/misc/convert_numbers_format_test.rb +4 -0
  106. data/test/mock_app/app/assets/config/manifest.js +0 -0
  107. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  108. data/test/mock_app/app/controllers/people_controller.rb +3 -1
  109. data/test/mock_app/config/application.rb +1 -0
  110. data/test/mock_app/config/routes.rb +4 -1
  111. data/test/mock_app/db/schema.rb +2 -0
  112. data/test/performance/list_cars_performance_test.rb +34 -0
  113. data/test/performance/list_people_performance_test.rb +31 -0
  114. data/test/performance_test_help.rb +3 -0
  115. data/test/test_helper.rb +2 -1
  116. metadata +22 -12
  117. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  118. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -5
@@ -11,7 +11,7 @@ module ActiveScaffold::Config
11
11
  attr_accessor :mark_all_mode
12
12
 
13
13
  def initialize(core_config)
14
- @core = core_config
14
+ super
15
15
  @mark_all_mode = self.class.mark_all_mode
16
16
  @core.model.send(:include, ActiveScaffold::MarkedModel) unless @core.model < ActiveScaffold::MarkedModel
17
17
  add_mark_column
@@ -1,5 +1,7 @@
1
1
  module ActiveScaffold
2
- # Exposes a +configure+ method that accepts a block and runs all contents of the block in two contexts, as opposed to the normal one. First, everything gets evaluated as part of the object including Configurable. Then, as a failover, missing methods and variables are evaluated in the original binding of the block.
2
+ # Exposes a +configure+ method that accepts a block and runs all contents of the block in two contexts,
3
+ # as opposed to the normal one. First, everything gets evaluated as part of the object including Configurable.
4
+ # Then, as a failover, missing methods and variables are evaluated in the original binding of the block.
3
5
  #
4
6
  # Note that this only works with "barewords". Constants, instance variables, and class variables are not currently supported in both contexts.
5
7
  #
@@ -22,8 +24,8 @@ module ActiveScaffold
22
24
  end
23
25
 
24
26
  def respond_to_missing?(name, include_all = false)
25
- if @configuration_binding
26
- @configuration_binding.respond_to?(name, include_all)
27
+ if defined? @configuration_binding
28
+ @configuration_binding&.respond_to?(name, include_all)
27
29
  else
28
30
  super
29
31
  end
@@ -61,15 +61,7 @@ module ActiveScaffold
61
61
 
62
62
  # association column constraint
63
63
  elsif column.association
64
- if column.association.habtm?
65
- active_scaffold_habtm_joins.concat column.includes
66
- elsif !column.association.polymorphic?
67
- if column.association.belongs_to?
68
- active_scaffold_preload.concat column.includes
69
- else
70
- active_scaffold_references.concat column.includes
71
- end
72
- end
64
+ join_from_association_constraint(column)
73
65
  hash_conditions.deep_merge!(condition_from_association_constraint(column.association, v))
74
66
 
75
67
  # regular column constraints
@@ -78,7 +70,7 @@ module ActiveScaffold
78
70
  conditions << [column.search_sql.collect { |search_sql| "#{search_sql} = ?" }.join(' OR '), *([v] * column.search_sql.size)]
79
71
  end
80
72
  # unknown-to-activescaffold-but-real-database-column constraint
81
- elsif active_scaffold_config.model.columns_hash[k.to_s] && params[column.name] != v
73
+ elsif active_scaffold_config._columns_hash[k.to_s] && params[column.name] != v
82
74
  hash_conditions.deep_merge!(k => v)
83
75
  else
84
76
  raise ActiveScaffold::MalformedConstraint, constraint_error(active_scaffold_config.model, k), caller
@@ -87,6 +79,18 @@ module ActiveScaffold
87
79
  conditions.reject(&:blank?)
88
80
  end
89
81
 
82
+ def join_from_association_constraint(column)
83
+ if column.association.habtm?
84
+ active_scaffold_habtm_joins.concat column.includes
85
+ elsif !column.association.polymorphic?
86
+ if column.association.belongs_to?
87
+ active_scaffold_preload.concat column.includes
88
+ else
89
+ active_scaffold_references.concat column.includes
90
+ end
91
+ end
92
+ end
93
+
90
94
  # We do NOT want to use .search_sql. If anything, search_sql will refer
91
95
  # to a human-searchable value on the associated record.
92
96
  def condition_from_association_constraint(association, value)
@@ -96,17 +100,15 @@ module ActiveScaffold
96
100
  #
97
101
  # please see the relevant tests for concrete examples.
98
102
 
99
- field = if association.belongs_to?
100
- association.foreign_key
101
- else
102
- association.klass.primary_key
103
+ field =
104
+ if association.belongs_to?
105
+ association.foreign_key
106
+ else
107
+ association.klass.primary_key
103
108
  end
104
109
 
105
110
  table = association.belongs_to? ? active_scaffold_config.model.table_name : association.table_name
106
-
107
- if association.primary_key
108
- value = association.klass.find(value).send(association.primary_key)
109
- end
111
+ value = association.klass.find(value).send(association.primary_key) if association.primary_key
110
112
 
111
113
  if association.polymorphic?
112
114
  unless value.is_a?(Array) && value.size == 2
@@ -151,7 +153,7 @@ module ActiveScaffold
151
153
  raise ActiveScaffold::MalformedConstraint, polymorphic_constraint_error(column.association), caller
152
154
  end
153
155
  record.send("#{k}=", v[0].constantize.find(v[1]))
154
- else # regular singular association
156
+ elsif !column.association.source_reflection&.options&.include?(:through) # regular singular association, or one-level through association
155
157
  record.send("#{k}=", column.association.klass.find(v))
156
158
 
157
159
  # setting the belongs_to side of a has_one isn't safe. if the has_one was already
@@ -7,20 +7,21 @@ module ActiveScaffold
7
7
  def setup_user_settings
8
8
  config = self.class.active_scaffold_config
9
9
  config.new_user_settings(user_settings_storage, params)
10
- unless ActiveScaffold.threadsafe
11
- config.actions.each do |action_name|
12
- conf_instance = config.send(action_name) rescue next # rubocop:disable Style/RescueModifier
13
- config.user.action_user_settings(conf_instance)
14
- end
10
+ return if ActiveScaffold.threadsafe
11
+ config.actions.each do |action_name|
12
+ conf_instance = config.send(action_name) rescue next # rubocop:disable Style/RescueModifier
13
+ config.user.action_user_settings(conf_instance)
15
14
  end
16
15
  end
17
16
 
18
17
  def active_scaffold_config
19
- setup_user_settings unless self.class.active_scaffold_config.user
20
- if ActiveScaffold.threadsafe
21
- self.class.active_scaffold_config.user
22
- else
23
- self.class.active_scaffold_config
18
+ @active_scaffold_config ||= begin
19
+ setup_user_settings unless self.class.active_scaffold_config.user
20
+ if ActiveScaffold.threadsafe
21
+ self.class.active_scaffold_config.user
22
+ else
23
+ self.class.active_scaffold_config
24
+ end
24
25
  end
25
26
  end
26
27
 
@@ -60,7 +61,13 @@ module ActiveScaffold
60
61
  active_scaffold_superclasses_blocks.each { |superblock| active_scaffold_config.configure(&superblock) }
61
62
  active_scaffold_config.sti_children = nil # reset sti_children if set in parent block
62
63
  active_scaffold_config.configure(&block) if block_given?
63
- active_scaffold_config._configure_sti unless active_scaffold_config.sti_children.nil?
64
+ active_scaffold_config.class.after_config_callbacks.each do |callback|
65
+ if callback.is_a?(Proc)
66
+ callback.call
67
+ elsif active_scaffold_config.respond_to?(callback)
68
+ active_scaffold_config.send(callback)
69
+ end
70
+ end
64
71
 
65
72
  # defines the attribute read methods on the model, so record.send() doesn't find protected/private methods instead
66
73
  # define_attribute_methods is safe to call multiple times since rails 4.0.4
@@ -90,10 +97,9 @@ module ActiveScaffold
90
97
  end
91
98
  end
92
99
  _add_sti_create_links if active_scaffold_config.add_sti_create_links?
93
- if ActiveScaffold.threadsafe
94
- active_scaffold_config._cache_lazy_values
95
- active_scaffold_config.deep_freeze!
96
- end
100
+ return unless ActiveScaffold.threadsafe
101
+ active_scaffold_config._cache_lazy_values
102
+ active_scaffold_config.deep_freeze!
97
103
  end
98
104
 
99
105
  module Prefixes
@@ -122,7 +128,8 @@ module ActiveScaffold
122
128
  end
123
129
  end
124
130
 
125
- # Create the automatic column links. Note that this has to happen when configuration is *done*, because otherwise the Nested module could be disabled. Actually, it could still be disabled later, couldn't it?
131
+ # Create the automatic column links. Note that this has to happen when configuration is *done*,
132
+ # because otherwise the Nested module could be disabled. Actually, it could still be disabled later, couldn't it?
126
133
  def links_for_associations
127
134
  return unless active_scaffold_config.actions.include?(:list) && active_scaffold_config.actions.include?(:nested)
128
135
  active_scaffold_config.columns.each do |column|
@@ -157,10 +164,13 @@ module ActiveScaffold
157
164
  else
158
165
  actions = controller.active_scaffold_config.actions unless controller == :polymorph
159
166
  actions ||= %i[create update show]
160
- column.actions_for_association_links.delete :new unless actions.include? :create
161
- column.actions_for_association_links.delete :edit unless actions.include? :update
162
- column.actions_for_association_links.delete :show unless actions.include? :show
163
- ActiveScaffold::DataStructures::ActionLink.new(nil, options.merge(:html_options => {:class => column.name}))
167
+ controller_actions = column.actions_for_association_links
168
+ controller_actions = controller_actions.dup if controller_actions.frozen?
169
+ controller_actions.delete :new unless actions.include? :create
170
+ controller_actions.delete :edit unless actions.include? :update
171
+ controller_actions.delete :show unless actions.include? :show
172
+ options.merge!(html_options: {class: column.name}, controller_actions: Set.new(controller_actions))
173
+ ActiveScaffold::DataStructures::ActionLink.new(nil, options)
164
174
  end
165
175
  end
166
176
 
@@ -230,12 +240,9 @@ module ActiveScaffold
230
240
  controller = "#{namespace}#{controller_name.camelize}Controller".constantize
231
241
  rescue NameError => error
232
242
  # Only rescue NameError associated with the controller constant not existing - not other compile errors
233
- if error.message["uninitialized constant #{controller}"]
234
- error_message << "#{namespace}#{controller_name.camelize}Controller"
235
- next
236
- else
237
- raise
238
- end
243
+ raise unless error.message["uninitialized constant #{controller}"]
244
+ error_message << "#{namespace}#{controller_name.camelize}Controller"
245
+ next
239
246
  end
240
247
  raise ActiveScaffold::ControllerNotFound, "#{controller} missing ActiveScaffold", caller unless controller.uses_active_scaffold?
241
248
  unless controller.active_scaffold_config.model.to_s == klass.to_s
@@ -258,10 +265,12 @@ module ActiveScaffold
258
265
  end
259
266
 
260
267
  def self.mongoid_column_type_cast(value, column)
268
+ return Time.zone.at(value.to_i) if value =~ /\A\d+\z/ && [Time, DateTime].include?(column.type)
261
269
  column.type.evolve value
262
270
  end
263
271
 
264
272
  def self.active_record_column_type_cast(value, column)
273
+ return Time.zone.at(value.to_i) if value =~ /\A\d+\z/ && %i[time datetime].include?(column.type)
265
274
  if Rails.version < '5.0'
266
275
  column.type_cast_from_user value
267
276
  elsif column.type.respond_to? :cast # jruby-jdbc and rails 5
@@ -68,7 +68,7 @@ module ActiveScaffold::DataStructures
68
68
  end
69
69
 
70
70
  def each_column(options = {}, &proc)
71
- columns = action.core.columns
71
+ columns = options[:core_columns] || action.core.columns
72
72
  self.unauthorized_columns = []
73
73
  options[:for] ||= columns.active_record_class
74
74
 
@@ -5,27 +5,33 @@ module ActiveScaffold::DataStructures
5
5
  # provides a quick way to set any property of the object from a hash
6
6
  def initialize(action, options = {})
7
7
  # set defaults
8
- self.action = action
9
- self.label = action
10
- self.confirm = false
11
- self.type = :collection
8
+ @action = action
9
+ @label = action
10
+ @confirm = false
11
+ @type = :collection
12
+ @method = :get
13
+ @crud_type =
14
+ case action&.to_sym
15
+ when :destroy then :delete
16
+ when :create, :new then :create
17
+ when :update, :edit then :update
18
+ else :read
19
+ end
20
+ @column = nil
21
+ @image = nil
22
+ @controller = nil
23
+ @parameters = nil
24
+ @dynamic_parameters = nil
25
+ @html_options = nil
26
+ @weight = 0
12
27
  self.inline = true
13
- self.method = :get
14
- self.crud_type = :delete if [:destroy].include?(action&.to_sym)
15
- self.crud_type = :create if %i[create new].include?(action&.to_sym)
16
- self.crud_type = :update if %i[edit update].include?(action&.to_sym)
17
- self.crud_type ||= :read
18
- self.column = nil
19
- self.image = nil
20
- self.dynamic_parameters = nil
21
- self.weight = 0
22
28
 
23
29
  # apply quick properties
24
30
  options.each_pair do |k, v|
25
31
  setter = "#{k}="
26
32
  send(setter, v) if respond_to? setter
27
33
  end
28
- self.toggle = self.action&.to_sym == :index && (parameters.present? || dynamic_parameters) unless options.include? :toggle
34
+ self.toggle = self.action&.to_sym == :index && !position && (parameters.present? || dynamic_parameters) unless options.include? :toggle
29
35
  end
30
36
 
31
37
  def initialize_copy(action_link)
@@ -72,7 +78,7 @@ module ActiveScaffold::DataStructures
72
78
  # what string to use to represent this action
73
79
  attr_writer :label
74
80
  def label
75
- @label.is_a?(Symbol) ? as_(@label) : @label
81
+ @label.is_a?(Symbol) ? ActiveScaffold::Registry.cache(:translations, @label) { as_(@label) } : @label
76
82
  end
77
83
 
78
84
  # image to use {:name => 'arrow.png', :size => '16x16'}
@@ -85,7 +91,8 @@ module ActiveScaffold::DataStructures
85
91
  end
86
92
 
87
93
  def confirm(label = '')
88
- @confirm.is_a?(String) ? @confirm : as_(@confirm, :label => label)
94
+ return @confirm if !confirm? || @confirm.is_a?(String)
95
+ ActiveScaffold::Registry.cache(:translations, @confirm) { as_(@confirm) } % {label: label}
89
96
  end
90
97
 
91
98
  def confirm?
@@ -202,6 +209,11 @@ module ActiveScaffold::DataStructures
202
209
  @keep_open
203
210
  end
204
211
 
212
+ # for links in singular associations, copied from
213
+ # column.actions_for_association_links, excluding
214
+ # actions not available in association's controller
215
+ attr_accessor :controller_actions
216
+
205
217
  # indicates that this a nested_link
206
218
  def nested_link?
207
219
  @column || parameters&.dig(:named_scope)
@@ -218,5 +230,11 @@ module ActiveScaffold::DataStructures
218
230
  @name_to_cache = name_to_cache unless frozen?
219
231
  end
220
232
  end
233
+
234
+ def freeze
235
+ # force generating cache_key, except for column's link without action, or polymorphic associations
236
+ name_to_cache if action && !column&.association&.polymorphic?
237
+ super
238
+ end
221
239
  end
222
240
  end
@@ -53,8 +53,8 @@ module ActiveScaffold::DataStructures
53
53
  if item.is_a?(ActiveScaffold::DataStructures::ActionLinks)
54
54
  collected = item[val]
55
55
  links << collected unless collected.nil?
56
- else
57
- links << item if item.action.to_s == val.to_s
56
+ elsif item.action.to_s == val.to_s
57
+ links << item
58
58
  end
59
59
  end
60
60
  links.first
@@ -66,8 +66,8 @@ module ActiveScaffold::DataStructures
66
66
  if item.is_a?(ActiveScaffold::DataStructures::ActionLinks)
67
67
  collected = item.find_duplicate(link)
68
68
  links << collected unless collected.nil?
69
- else
70
- links << item if item.action == link.action && item.static_controller? && item.controller == link.controller && item.parameters == link.parameters
69
+ elsif item.action == link.action && item.static_controller? && item.controller == link.controller && item.parameters == link.parameters
70
+ links << item
71
71
  end
72
72
  end
73
73
  links.first
@@ -100,12 +100,10 @@ module ActiveScaffold::DataStructures
100
100
  @set.sort_by(&:weight).send(method) do |item|
101
101
  if item.is_a?(ActiveScaffold::DataStructures::ActionLinks) && !options[:groups]
102
102
  item.each(options, &block)
103
+ elsif options[:include_set]
104
+ yield item, @set
103
105
  else
104
- if options[:include_set]
105
- yield item, @set
106
- else
107
- yield item
108
- end
106
+ yield item
109
107
  end
110
108
  end
111
109
  end
@@ -147,13 +145,13 @@ module ActiveScaffold::DataStructures
147
145
 
148
146
  def method_missing(name, *args, &block)
149
147
  return super if name =~ /[!?]$/
150
- class_eval %{
148
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
151
149
  def #{name}(label = nil) # rubocop:disable Style/CommentedKeyword
152
150
  @#{name} ||= subgroup('#{name}'.to_sym, label)
153
151
  yield @#{name} if block_given?
154
152
  @#{name}
155
153
  end
156
- }
154
+ METHOD
157
155
  send(name, args.first, &block)
158
156
  end
159
157
 
@@ -10,19 +10,26 @@ module ActiveScaffold::DataStructures::Association
10
10
  !polymorphic?
11
11
  end
12
12
 
13
- def klass
14
- @association.klass unless polymorphic?
13
+ def klass(record = nil)
14
+ if polymorphic?
15
+ record&.send(foreign_type)&.constantize
16
+ else
17
+ @association.klass
18
+ end
19
+ rescue NameError => e
20
+ Rails.logger.warn "#{e.message}\n#{e.backtrace.join("\n")}"
21
+ nil
15
22
  end
16
23
 
17
24
  def belongs_to?
18
25
  @association.macro == :belongs_to
19
26
  end
20
27
 
21
- def has_one?
28
+ def has_one? # rubocop:disable Naming/PredicateName
22
29
  @association.macro == :has_one
23
30
  end
24
31
 
25
- def has_many?
32
+ def has_many? # rubocop:disable Naming/PredicateName
26
33
  @association.macro == :has_many
27
34
  end
28
35
 
@@ -34,10 +41,22 @@ module ActiveScaffold::DataStructures::Association
34
41
  !collection?
35
42
  end
36
43
 
44
+ def collection?
45
+ has_many? || habtm?
46
+ end
47
+
37
48
  def through?
38
49
  false
39
50
  end
40
51
 
52
+ def through_singular?
53
+ through? && !through_reflection.collection?
54
+ end
55
+
56
+ def through_collection?
57
+ through? && through_reflection.collection?
58
+ end
59
+
41
60
  def polymorphic?
42
61
  false
43
62
  end
@@ -52,6 +71,8 @@ module ActiveScaffold::DataStructures::Association
52
71
 
53
72
  def scope; end
54
73
 
74
+ def as; end
75
+
55
76
  def respond_to_target?
56
77
  false
57
78
  end
@@ -81,12 +102,13 @@ module ActiveScaffold::DataStructures::Association
81
102
  end
82
103
 
83
104
  def reverse_association(klass = nil)
84
- assoc = if polymorphic?
85
- get_reverse(klass) unless klass.nil?
86
- else
87
- return unless reverse_name = reverse(klass)
88
- reflect_on_association(reverse_name)
89
- end
105
+ assoc =
106
+ if polymorphic?
107
+ get_reverse(klass) unless klass.nil?
108
+ else
109
+ reverse_name = reverse(klass)
110
+ reflect_on_association(reverse_name) if reverse_name
111
+ end
90
112
  self.class.new(assoc) if assoc
91
113
  end
92
114
 
@@ -114,13 +136,13 @@ module ActiveScaffold::DataStructures::Association
114
136
  associations = self.class.reflect_on_all_associations(klass)
115
137
  # collect associations that point back to this model and use the same foreign_key
116
138
  associations.each_with_object([]) do |assoc, reverse_matches|
117
- reverse_matches << assoc if reverse_match? assoc
139
+ reverse_matches << assoc if assoc != @association && reverse_match?(assoc)
118
140
  end
119
141
  end
120
142
 
121
143
  def reverse_match?(assoc)
122
- return false if assoc == @association
123
- return false unless assoc.polymorphic? || assoc.class_name == inverse_klass&.name
144
+ return assoc.name == as if as || assoc.polymorphic?
145
+ return false if assoc.class_name != inverse_klass&.name
124
146
 
125
147
  if through?
126
148
  reverse_through_match?(assoc)