active_scaffold 3.6.0.pre → 3.6.0.rc1

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