active_scaffold 3.7.4 → 3.7.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9206609200e1c9330a6e04b1731300dad5fcba8a52c70ae26ef6ba6427da4c25
4
- data.tar.gz: 0b501f82598b99ff587b1fa484d017a73f1fd018b5a26a7968c065d0152ae74b
3
+ metadata.gz: ba64ea5cfd0c7476b2a534dd60d646c9b25b00f86278873e132d930336007673
4
+ data.tar.gz: 5ec04a9180e01392a6718ba25453a2731819a53551ef15de1e58e207533b1881
5
5
  SHA512:
6
- metadata.gz: '08c1c4a3b4dad7c731793ebecd4e238a36ee49e340964c8321a88b562fafbf0b12d7992501c5ffad8efa60820a40e80879f0c9e60715cc1da2e31a5c764781bc'
7
- data.tar.gz: 310c5bf214800a98efd1d7af45b771608ce85cdf27db3df8437a0ea9cbabb243f2df8d8ee3603c81a9e43a76ba09dcaae20df26aa3a1b0df9bf0b18f2c244bab
6
+ metadata.gz: 67a8322a087fbb94b4c2b51d2bb8a4687fe76e0d4c73eae18d57b30d2457fb85bbe30d67c5b84a1e3b6dfd0100710b79cd304d81cac087d49f9f0967900343df
7
+ data.tar.gz: ff5d7ae043ba814460a375d3f146115fc8b9fd0a21b5d9ea7c31410ff52b85c83641d27ac5ab9c99724b22e38265542eb141c8eafd64ba173e76e0c4145ecefb
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,17 @@
1
+ = 3.7.5
2
+ - Fix always show search for nested list on multi-level through associations
3
+ - Support changing step, min and max options with column options or search_ui options for decimal and integer search_ui
4
+ - Support null and not null comparators in date and datetime search_ui
5
+ - Support defining options_for_association_conditions, association_klass_scoped and active_scaffold_enum_options helpers prefixed with model name. Useful when clear_helpers is not called in ApplicationController.
6
+ - Fix class for columns with form_ui or css_class when refreshing column
7
+ - Eval after_config_callback proc in the context of AS config
8
+ - Fix registering constrained fields on polymorphic association
9
+ - Improve applying constraints for polymorphic associations when constraining with multiple ids, set only the foreign type
10
+ - Support prefixing helpers with base class for models using STI besides model name prefix
11
+ - Support create when nested on through association when source association is singular, as rails creates the joint model
12
+ - Allow to set controller nil for association columns to STI models
13
+ - Add session argument to condition_for_column and condition_for_<column>_column, so custom conditions on columns may use the session, make it optional so it's backwards compatible
14
+
1
15
  = 3.7.4
2
16
  - Support loading both jquery and jquery-ui externally
3
17
  - Fix subquery in search with STI
@@ -5,7 +5,7 @@
5
5
  <table>
6
6
  <tbody class="before-header" id="<%= before_header_id -%>">
7
7
  <% if active_scaffold_config.list.always_show_search %>
8
- <% old_record, @record = @record, new_model %>
8
+ <% old_record, @record = @record, active_scaffold_config.model.new %>
9
9
  <tr>
10
10
  <td>
11
11
  <div class="active-scaffold show_search-view <%= "#{id_from_controller params[:controller]}-view" %> view">
@@ -1,9 +1,10 @@
1
1
  <%
2
- column = if render_field.is_a? ActiveScaffold::DataStructures::Column
3
- render_field
4
- else
5
- active_scaffold_config.columns[render_field]
6
- end
2
+ column =
3
+ if render_field.is_a? ActiveScaffold::DataStructures::Column
4
+ render_field
5
+ else
6
+ active_scaffold_config.columns[render_field]
7
+ end
7
8
  return unless @main_columns.include? column.name
8
9
  @rendered ||= Set.new
9
10
  return if @rendered.include? column.name
@@ -14,13 +15,15 @@
14
15
  renders_as = column_renders_as(column)
15
16
  form_ui = column.form_ui
16
17
  end
18
+
19
+ column_css_class = column.css_class unless column.css_class.nil? || column.css_class.is_a?(Proc)
17
20
  options = {field_class: "#{column.name}-input", hidden: form_ui == :hidden}
18
21
  options[:subform_class] = "#{column.name}-sub-form" if column.association
19
22
  options[:attrs] =
20
23
  if renders_as == :subform
21
- active_scaffold_subform_attributes(column, (column.css_class unless column.css_class.is_a?(Proc)))
24
+ active_scaffold_subform_attributes(column, column_css_class)
22
25
  else
23
- {class: 'form-element', id: ''}
26
+ {class: "form-element #{:required if column.required?(@form_action)} #{column.form_ui} #{column_css_class}", id: ''}
24
27
  end
25
28
  html =
26
29
  if scope
@@ -17,6 +17,7 @@ module ActiveScaffold::Actions
17
17
  base.helper_method :embedded?
18
18
  base.helper_method :loading_embedded?
19
19
  base.helper_method :calculate_query
20
+ base.helper_method :calculate_subquery
20
21
  base.helper_method :new_model
21
22
  base.helper_method :touch_device?
22
23
  base.helper_method :hover_via_click?
@@ -134,8 +135,8 @@ module ActiveScaffold::Actions
134
135
  parent = parent_model.new
135
136
  copy_attributes(find_if_allowed(params[:parent_id], :read, parent_model), parent) if params[:parent_id]
136
137
  parent.id = params[:parent_id]
137
- parent = update_record_from_params(parent, cfg.send(params[:parent_id] ? :update : :create).columns, params[:record], true) if @column.send_form_on_update_column
138
138
  apply_constraints_to_record(parent) unless params[:parent_id]
139
+ parent = update_record_from_params(parent, cfg.send(params[:parent_id] ? :update : :create).columns, params[:record], true) if @column.send_form_on_update_column
139
140
  if association.collection?
140
141
  record.send(association.name) << parent
141
142
  else
@@ -93,8 +93,10 @@ module ActiveScaffold::Actions
93
93
  def do_create(options = {})
94
94
  attributes = options[:attributes] || params[:record]
95
95
  active_scaffold_config.model.transaction do
96
- @record = update_record_from_params(new_model, active_scaffold_config.create.columns, attributes)
96
+ @record = new_model
97
+ # before assign params, to set foreign_type of constraints in polymorphic association with multiple id
97
98
  apply_constraints_to_record(@record, :allow_autosave => true)
99
+ @record = update_record_from_params(@record, active_scaffold_config.create.columns, attributes)
98
100
  create_association_with_parent(@record) if nested?
99
101
  before_create_save(@record)
100
102
  # errors to @record can be added by update_record_from_params when association fails to set and ActiveRecord::RecordNotSaved is raised
@@ -157,7 +157,7 @@ module ActiveScaffold::Actions
157
157
  search_params.each do |key, value|
158
158
  next unless columns.include? key
159
159
  column = active_scaffold_config.columns[key]
160
- search_condition = self.class.condition_for_column(column, value, text_search)
160
+ search_condition = self.class.condition_for_column(column, value, text_search, session)
161
161
  next if search_condition.blank?
162
162
 
163
163
  active_scaffold_conditions << search_condition
@@ -8,17 +8,20 @@ module ActiveScaffold
8
8
 
9
9
  # Returns the current constraints
10
10
  def active_scaffold_constraints
11
- @active_scaffold_constraints ||= active_scaffold_embedded_params[:constraints] || {}
11
+ @active_scaffold_constraints ||= active_scaffold_embedded_params[:constraints]&.to_unsafe_h || {}
12
12
  end
13
13
 
14
- def register_constraint?(column_name, value)
15
- if params_hash?(value)
16
- false
17
- elsif value.is_a?(Array)
14
+ def columns_from_constraint(column_name, value)
15
+ return if params_hash?(value)
16
+ if value.is_a?(Array)
18
17
  column = active_scaffold_config.columns[column_name]
19
- column && value.size > (column.association&.polymorphic? ? 2 : 1)
18
+ if column&.association&.polymorphic?
19
+ [column.association.foreign_type.to_sym, (column.name if value.size == 2)].compact
20
+ elsif column && value.size == 1
21
+ column.name
22
+ end
20
23
  else
21
- true
24
+ column_name.to_sym
22
25
  end
23
26
  end
24
27
 
@@ -31,7 +34,7 @@ module ActiveScaffold
31
34
  # we do NOT register the constraint column, as records will have different values in the column.
32
35
  def register_constraints_with_action_columns(constrained_fields = nil)
33
36
  constrained_fields ||= []
34
- constrained_fields |= active_scaffold_constraints.select { |k, v| register_constraint?(k, v) }.keys.collect(&:to_sym)
37
+ constrained_fields |= active_scaffold_constraints.flat_map { |k, v| columns_from_constraint(k, v) }.compact
35
38
  exclude_actions = []
36
39
  %i[list update].each do |action_name|
37
40
  if active_scaffold_config.actions.include? action_name
@@ -161,12 +164,16 @@ module ActiveScaffold
161
164
  column = config.columns[k]
162
165
  if column&.association
163
166
  if column.association.collection?
164
- record.send(k.to_s).send(:<<, column.association.klass.find(v))
167
+ record.send(k.to_s).send(:<<, column.association.klass.find(v)) unless column.association.nested?
165
168
  elsif column.association.polymorphic?
166
169
  unless v.is_a?(Array) && v.size >= 2
167
170
  raise ActiveScaffold::MalformedConstraint, polymorphic_constraint_error(column.association), caller
168
171
  end
169
- record.send("#{k}=", v[0].constantize.find(v[1])) if v.size == 2
172
+ if v.size == 2
173
+ record.send("#{k}=", v[0].constantize.find(v[1]))
174
+ else
175
+ record.send("#{column.association.foreign_type}=", v[0])
176
+ end
170
177
  elsif !column.association.source_reflection&.options&.include?(:through) && # regular singular association, or one-level through association
171
178
  !v.is_a?(Array)
172
179
  record.send("#{k}=", column.association.klass.find(v))
@@ -177,7 +184,7 @@ module ActiveScaffold
177
184
  # note that we can't take the extra step to correct this unless we're permitted to
178
185
  # run operations where activerecord auto-saves the object.
179
186
  reverse = column.association.reverse_association
180
- if reverse.singular? && !reverse.belongs_to? && options[:allow_autosave]
187
+ if reverse&.singular? && !reverse.belongs_to? && options[:allow_autosave]
181
188
  record.send(k).send("#{reverse.name}=", record)
182
189
  end
183
190
  end
@@ -63,7 +63,7 @@ module ActiveScaffold
63
63
  active_scaffold_config.configure(&block) if block_given?
64
64
  active_scaffold_config.class.after_config_callbacks.each do |callback|
65
65
  if callback.is_a?(Proc)
66
- callback.call
66
+ instance_eval(&callback)
67
67
  elsif active_scaffold_config.respond_to?(callback)
68
68
  active_scaffold_config.send(callback)
69
69
  end
@@ -46,6 +46,10 @@ module ActiveScaffold::DataStructures::Association
46
46
  false
47
47
  end
48
48
 
49
+ def nested?
50
+ false
51
+ end
52
+
49
53
  def through_singular?
50
54
  through? && !through_reflection.collection?
51
55
  end
@@ -10,6 +10,10 @@ module ActiveScaffold::DataStructures::Association
10
10
  @association.options[:through].present?
11
11
  end
12
12
 
13
+ def nested?
14
+ @association.nested?
15
+ end
16
+
13
17
  def readonly?
14
18
  scope_values[:readonly]
15
19
  end
@@ -90,15 +90,22 @@ module ActiveScaffold::DataStructures
90
90
  delegate :name, :belongs_to?, :has_one?, :has_many?, :habtm?, :readonly?, :to => :association
91
91
 
92
92
  # A through association with has_one or has_many as source association
93
- # create cannot be called in nested through associations, and not-nested through associations
94
- # unless is through singular or create columns include through reflection of reverse association
95
- # e.g. customer -> networks -> firewall, reverse is firewall -> network -> customer,
96
- # firewall can be created if create columns include network
93
+ # create cannot be called in nested through associations, and not-nested through associations, unless:
94
+ # 1. is through singular and source association has reverse, e.g.:
95
+ # Employee belongs to vendor, Vendor has many rates, Rate belongs to vendor, Employee has many rates through vendor
96
+ # Rates association through singular association vendor, source association in Vendor (rates) has reverse (vendor in Rate)
97
+ # AS will assign the vendor of the employee to the new Rate
98
+ # 2. source association is singular, e.g.:
99
+ # Customer has many networks, Network has one (or belongs to) firewall, Customer has many firewalls through networks
100
+ # 3. create columns include through association of reverse association, e.g.:
101
+ # Vendor has many employees, Employee has many rates, Vendor has many rates through employees, Rate has one vendor through employee
102
+ # RatesController has employee in create action columns (reverse is vendor, and through association employee is in create form).
97
103
  def readonly_through_association?(columns)
98
104
  return false unless through_association?
99
105
  return true if association.through_reflection.options[:through] # create not possible, too many levels
100
106
  return true if association.source_reflection.options[:through] # create not possible, too many levels
101
107
  return false if create_through_singular? # create allowed, AS has code for this
108
+ return false unless association.source_reflection.collection? # create allowed if source is singular, rails creates joint model
102
109
 
103
110
  # create allowed only if through reflection in record to be created is included in create columns
104
111
  !child_association || !columns.include?(child_association.through_reflection.name)
@@ -96,11 +96,14 @@ module ActiveScaffold
96
96
  # Generates an SQL condition for the given ActiveScaffold column based on
97
97
  # that column's database type (or form_ui ... for virtual columns?).
98
98
  # TODO: this should reside on the column, not the controller
99
- def condition_for_column(column, value, text_search = :full)
99
+ def condition_for_column(column, value, text_search, session)
100
100
  like_pattern = like_pattern(text_search)
101
101
  value = value.with_indifferent_access if value.is_a? Hash
102
- if respond_to?("condition_for_#{column.name}_column")
103
- return send("condition_for_#{column.name}_column", column, value, like_pattern)
102
+ column_method = "condition_for_#{column.name}_column"
103
+ if respond_to?(column_method)
104
+ args = [column, value, like_pattern]
105
+ args << session if method(column_method).arity == 4
106
+ return send("condition_for_#{column.name}_column", *args)
104
107
  end
105
108
  return unless column&.search_sql && value.present?
106
109
  search_ui = column.search_ui || column.column_type
@@ -363,6 +366,8 @@ module ActiveScaffold
363
366
 
364
367
  if column.search_sql.is_a? Proc
365
368
  column.search_sql.call(from_value, to_value, operator)
369
+ elsif ActiveScaffold::Finder::NULL_COMPARATORS.include?(value['opt'])
370
+ condition_for_null_type(column, value['opt'], like_pattern)
366
371
  elsif operator.nil?
367
372
  ['%<search_sql>s BETWEEN ? AND ?', from_value, to_value] unless from_value.nil? || to_value.nil?
368
373
  else
@@ -650,7 +655,7 @@ module ActiveScaffold
650
655
  @last_modified = query.maximum(:updated_at)
651
656
  end
652
657
 
653
- def calculate_query(id_condition = true)
658
+ def calculate_subquery(id_condition = true)
654
659
  conditions = all_conditions(id_condition)
655
660
  includes = active_scaffold_config.list.count_includes
656
661
  includes ||= active_scaffold_references if conditions.present?
@@ -658,8 +663,11 @@ module ActiveScaffold
658
663
  left_joins += includes if includes
659
664
  primary_key = active_scaffold_config.primary_key
660
665
  subquery = append_to_query(beginning_of_chain, :conditions => conditions, :joins => joins_for_finder, :left_joins => left_joins, :select => active_scaffold_config.columns[primary_key].field)
661
- subquery = subquery.unscope(:order)
662
- active_scaffold_config.model.where(primary_key => subquery)
666
+ subquery.unscope(:order)
667
+ end
668
+
669
+ def calculate_query(id_condition = true)
670
+ active_scaffold_config.model.where(active_scaffold_config.primary_key => calculate_subquery(id_condition))
663
671
  end
664
672
 
665
673
  def append_to_query(relation, options)
@@ -99,7 +99,7 @@ module ActiveScaffold
99
99
  def action_link_to_inline_form(link, record)
100
100
  link = link.dup
101
101
  associated = record.send(link.column.association.name)
102
- if link.column.association&.polymorphic?
102
+ if link.column.association&.polymorphic? || link.controller.nil?
103
103
  link.controller = controller_path_for_activerecord(associated.class)
104
104
  return link if link.controller.nil?
105
105
  end
@@ -1,3 +1,4 @@
1
+
1
2
  module ActiveScaffold
2
3
  module Helpers
3
4
  module AssociationHelpers
@@ -12,6 +13,11 @@ module ActiveScaffold
12
13
  end
13
14
  end
14
15
 
16
+ def association_helper_method(association, method)
17
+ model = association.inverse_klass
18
+ override_helper_per_model(method, model)
19
+ end
20
+
15
21
  # Provides a way to honor the :conditions on an association while searching the association's klass
16
22
  def association_options_find(association, conditions = nil, klass = nil, record = nil)
17
23
  if klass.nil? && association.polymorphic?
@@ -24,9 +30,9 @@ module ActiveScaffold
24
30
  klass ||= association.klass
25
31
  end
26
32
 
27
- conditions ||= options_for_association_conditions(association, record)
33
+ conditions ||= send(association_helper_method(association, :options_for_association_conditions), association, record)
28
34
  cache_association_options(association, conditions, klass, cache) do
29
- klass = association_klass_scoped(association, klass, record)
35
+ klass = send(association_helper_method(association, :association_klass_scoped), association, klass, record)
30
36
  relation = klass.where(conditions)
31
37
  column = column_for_association(association, record)
32
38
  if column&.includes
@@ -80,7 +86,7 @@ module ActiveScaffold
80
86
  end
81
87
 
82
88
  def options_for_association_count(association, record)
83
- conditions = options_for_association_conditions(association, record)
89
+ conditions = send(association_helper_method(association, :options_for_association_conditions), association, record)
84
90
  association_options_count(association, conditions)
85
91
  end
86
92
 
@@ -486,7 +486,8 @@ module ActiveScaffold
486
486
  record = html_options.delete(:object)
487
487
  options[:selected] = record.send(column.name)
488
488
  options[:object] = record
489
- options_for_select = active_scaffold_enum_options(column, record, ui_options: ui_options).collect do |text, value|
489
+ enum_options_method = override_helper_per_model(:active_scaffold_enum_options, record.class)
490
+ options_for_select = send(enum_options_method, column, record, ui_options: ui_options).collect do |text, value|
490
491
  active_scaffold_translated_option(column, text, value)
491
492
  end
492
493
  html_options.merge!(ui_options[:html_options] || {})
@@ -535,7 +536,8 @@ module ActiveScaffold
535
536
  if column.association
536
537
  sorted_association_options_find(column.association, nil, record)
537
538
  else
538
- active_scaffold_enum_options(column, record, ui_options: ui_options)
539
+ enum_options_method = override_helper_per_model(:active_scaffold_enum_options, record.class)
540
+ send(enum_options_method, column, record, ui_options: ui_options)
539
541
  end
540
542
 
541
543
  selected = record.send(column.association.name) if column.association
@@ -55,6 +55,8 @@ module ActiveScaffold
55
55
  when 'PAST', 'FUTURE'
56
56
  from, to = controller.class.datetime_from_to(column, value)
57
57
  "#{column.active_record_class.human_attribute_name(column.name)} #{as_('BETWEEN'.downcase).downcase} #{I18n.l(from)} - #{I18n.l(to)}"
58
+ when 'null', 'not_null'
59
+ "#{column.active_record_class.human_attribute_name(column.name)} #{as_(value['opt'].downcase).downcase}"
58
60
  else
59
61
  from, to = controller.class.datetime_from_to(column, value)
60
62
  "#{column.active_record_class.human_attribute_name(column.name)} #{as_(value['opt'].downcase).downcase} #{I18n.l(from)} #{value['opt'] == 'BETWEEN' ? '- ' + I18n.l(to) : ''}"
@@ -85,7 +85,8 @@ module ActiveScaffold
85
85
  [r.send(method), r.id]
86
86
  end
87
87
  else
88
- select_options = active_scaffold_enum_options(column, record, ui_options: ui_options).collect do |text, value|
88
+ enum_options_method = override_helper_per_model(:active_scaffold_enum_options, record.class)
89
+ select_options = send(enum_options_method, column, record, ui_options: ui_options).collect do |text, value|
89
90
  active_scaffold_translated_option(column, text, value)
90
91
  end
91
92
  end
@@ -103,7 +104,8 @@ module ActiveScaffold
103
104
  select_options = sorted_association_options_find(column.association, false, record)
104
105
  else
105
106
  method = column.name
106
- select_options = active_scaffold_enum_options(column, record, ui_options: ui_options).collect do |text, value|
107
+ enum_options_method = override_helper_per_model(:active_scaffold_enum_options, record.class)
108
+ select_options = send(enum_options_method, column, record, ui_options: ui_options).collect do |text, value|
107
109
  active_scaffold_translated_option(column, text, value)
108
110
  end
109
111
  end
@@ -242,11 +244,13 @@ module ActiveScaffold
242
244
  alias active_scaffold_search_string active_scaffold_search_range
243
245
 
244
246
  def active_scaffold_search_integer(column, options, ui_options: column.options)
245
- active_scaffold_search_range(column, options, :number_field_tag, {step: '1'}, ui_options: ui_options) # rubocop:disable Style/BracesAroundHashParameters
247
+ number_opts = ui_options.slice(:step, :min, :max).reverse_merge(step: '1')
248
+ active_scaffold_search_range(column, options, :number_field_tag, number_opts, ui_options: ui_options)
246
249
  end
247
250
 
248
251
  def active_scaffold_search_decimal(column, options, ui_options: column.options)
249
- active_scaffold_search_range(column, options, :number_field_tag, {step: :any}, ui_options: ui_options) # rubocop:disable Style/BracesAroundHashParameters
252
+ number_opts = ui_options.slice(:step, :min, :max).reverse_merge(step: :any)
253
+ active_scaffold_search_range(column, options, :number_field_tag, number_opts, ui_options: ui_options)
250
254
  end
251
255
  alias active_scaffold_search_float active_scaffold_search_decimal
252
256
 
@@ -255,7 +259,7 @@ module ActiveScaffold
255
259
  'number' => 1, 'unit' => 'DAYS', 'range' => nil}
256
260
  current_search.merge!(options[:value]) unless options[:value].nil?
257
261
  tags = [
258
- active_scaffold_search_datetime_comparator_tag(column, options, current_search),
262
+ active_scaffold_search_datetime_comparator_tag(column, options, current_search, ui_options: column.options),
259
263
  active_scaffold_search_datetime_trend_tag(column, options, current_search),
260
264
  active_scaffold_search_datetime_numeric_tag(column, options, current_search, ui_options: ui_options, field_ui: field_ui),
261
265
  active_scaffold_search_datetime_range_tag(column, options, current_search)
@@ -275,13 +279,17 @@ module ActiveScaffold
275
279
  active_scaffold_search_datetime(column, options, ui_options: ui_options, field_ui: :date)
276
280
  end
277
281
 
278
- def active_scaffold_search_datetime_comparator_options(column)
282
+ def active_scaffold_search_datetime_comparator_options(column, ui_options: column.options)
279
283
  select_options = ActiveScaffold::Finder::DATE_COMPARATORS.collect { |comp| [as_(comp.downcase.to_sym), comp] }
280
- select_options + ActiveScaffold::Finder::NUMERIC_COMPARATORS.collect { |comp| [as_(comp.downcase.to_sym), comp] }
284
+ select_options.concat(ActiveScaffold::Finder::NUMERIC_COMPARATORS.collect { |comp| [as_(comp.downcase.to_sym), comp] })
285
+ if include_null_comparators? column, ui_options: ui_options
286
+ select_options.concat(ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] })
287
+ end
288
+ select_options
281
289
  end
282
290
 
283
- def active_scaffold_search_datetime_comparator_tag(column, options, current_search)
284
- choices = options_for_select(active_scaffold_search_datetime_comparator_options(column), current_search['opt'])
291
+ def active_scaffold_search_datetime_comparator_tag(column, options, current_search, ui_options: column.options)
292
+ choices = options_for_select(active_scaffold_search_datetime_comparator_options(column, ui_options: ui_options), current_search['opt'])
285
293
  select_tag("#{options[:name]}[opt]", choices, id: "#{options[:id]}_opt", class: 'as_search_range_option as_search_date_time_option')
286
294
  end
287
295
 
@@ -76,15 +76,9 @@ module ActiveScaffold
76
76
  link_to label, '#', :data => data, :style => 'display: none;', :class => 'as-js-button visibility-toggle'
77
77
  end
78
78
 
79
- def list_row_class_method(record)
80
- return @_list_row_class_method if defined? @_list_row_class_method
81
- class_override_helper = "#{clean_class_name(record.class.name)}_list_row_class"
82
- @_list_row_class_method = (class_override_helper if respond_to?(class_override_helper))
83
- end
84
-
85
79
  def list_row_class(record)
86
- class_override_helper = list_row_class_method(record)
87
- class_override_helper ? send(class_override_helper, record) : ''
80
+ class_override_helper = override_helper_per_model(:list_row_class, record.class)
81
+ class_override_helper != :list_row_class ? send(class_override_helper, record) : ''
88
82
  end
89
83
 
90
84
  def list_row_attributes(tr_class, tr_id, data_refresh)
@@ -159,21 +153,22 @@ module ActiveScaffold
159
153
  name.underscore.tr('/', '_')
160
154
  end
161
155
 
162
- # the naming convention for overriding with helpers
163
- def override_helper_name(column, suffix, class_prefix = false)
164
- "#{clean_class_name(column.active_record_class.name) + '_' if class_prefix}#{clean_column_name(column.name)}_#{suffix}"
156
+ def override_helper_per_model(method, model, cache_keys = nil)
157
+ cache_keys ||= [method, model.name]
158
+ ActiveScaffold::Registry.cache(*cache_keys) do
159
+ model_names = [model.name]
160
+ model_names << model.base_class.name if model.base_class != model
161
+ method_with_class = model_names.find do |model_name|
162
+ method_with_class = "#{clean_class_name(model_name)}_#{method}"
163
+ break method_with_class if respond_to?(method_with_class)
164
+ end
165
+ method_with_class || (method if respond_to?(method))
166
+ end
165
167
  end
166
168
 
167
169
  def override_helper(column, suffix)
168
- ActiveScaffold::Registry.cache suffix, column.cache_key do
169
- method_with_class = override_helper_name(column, suffix, true)
170
- if respond_to?(method_with_class)
171
- method_with_class
172
- else
173
- method = override_helper_name(column, suffix)
174
- method if respond_to?(method)
175
- end
176
- end
170
+ method = "#{clean_column_name(column.name)}_#{suffix}"
171
+ override_helper_per_model(method, column.active_record_class, [suffix, column.cache_key])
177
172
  end
178
173
 
179
174
  def history_state
@@ -2,7 +2,7 @@ module ActiveScaffold
2
2
  module Version
3
3
  MAJOR = 3
4
4
  MINOR = 7
5
- PATCH = 4
5
+ PATCH = 5
6
6
  FIX = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, FIX].compact.join('.')
@@ -2,10 +2,11 @@ require 'test_helper'
2
2
 
3
3
  class FormColumnHelpersTest < ActionView::TestCase
4
4
  include ActiveScaffold::Helpers::FormColumnHelpers
5
+ include ActiveScaffold::Helpers::ViewHelpers
5
6
 
6
7
  def setup
7
8
  @column = ActiveScaffold::DataStructures::Column.new(:a, ModelStub)
8
- @record = stub(:a => nil)
9
+ @record = ModelStub.new(a: nil)
9
10
  end
10
11
 
11
12
  def test_choices_for_select_form_ui_for_simple_column
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_scaffold
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.4
4
+ version: 3.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Many, see README
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-20 00:00:00.000000000 Z
11
+ date: 2024-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails