active_scaffold 3.7.3.1 → 3.7.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19423579470e1bb8a461f8e636f6f8fd78eaecfd9bcbd369308ae6e3e5579d9e
4
- data.tar.gz: cd1c919152e1548b5ec36713d4ed6e2bed68e9c442b7d4d8b2ec623446a4a876
3
+ metadata.gz: ba64ea5cfd0c7476b2a534dd60d646c9b25b00f86278873e132d930336007673
4
+ data.tar.gz: 5ec04a9180e01392a6718ba25453a2731819a53551ef15de1e58e207533b1881
5
5
  SHA512:
6
- metadata.gz: be7499f2ce41db308452898b8c09d701891659d8a13ef179cc5be022db3b15f1db1f28e25a6f7b160521bf50fa3b258688a255bffcc4247a0e51cc1fb62efaef
7
- data.tar.gz: ca811c9dc3c114ae1a5b09456524fa46ae0d59b147ca9a8c54ea0b170ba243f7f5b7ed7ce77397cf6744b47ad88ae7d30ce4618dd69e98d95a5e1503e592aabb
6
+ metadata.gz: 67a8322a087fbb94b4c2b51d2bb8a4687fe76e0d4c73eae18d57b30d2457fb85bbe30d67c5b84a1e3b6dfd0100710b79cd304d81cac087d49f9f0967900343df
7
+ data.tar.gz: ff5d7ae043ba814460a375d3f146115fc8b9fd0a21b5d9ea7c31410ff52b85c83641d27ac5ab9c99724b22e38265542eb141c8eafd64ba173e76e0c4145ecefb
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,21 @@
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
+
15
+ = 3.7.4
16
+ - Support loading both jquery and jquery-ui externally
17
+ - Fix subquery in search with STI
18
+
1
19
  = 3.7.3.1
2
20
  - Fix search, view was broken when reset_form was added
3
21
 
@@ -3,18 +3,20 @@
3
3
  when :jquery
4
4
  require_asset "getprototypeof"
5
5
  require_asset "jquery.ba-throttle-debounce"
6
- if Jquery::Rails.const_defined? 'JQUERY_UI_VERSION'
7
- require_asset "jquery-ui"
8
- elsif Jquery.const_defined? 'Ui'
9
- jquery_ui_prefix = Jquery::Ui::Rails::VERSION < '5.0.0' ? 'jquery.ui.' : 'jquery-ui/'
10
- jquery_ui_widgets_prefix = Jquery::Ui::Rails::VERSION >= '6.0.0' ? 'widgets/' : ''
11
- require_asset "#{jquery_ui_prefix}core"
12
- require_asset "#{jquery_ui_prefix}effect"
13
- require_asset "#{jquery_ui_prefix}effects/effect-highlight" if Jquery::Ui::Rails::VERSION >= '6.0.0'
14
- require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}sortable"
15
- require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}draggable"
16
- require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}droppable"
17
- require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}datepicker"
6
+ if Object.const_defined?('Jquery')
7
+ if Jquery.const_defined?('Rails') && Jquery::Rails.const_defined?('JQUERY_UI_VERSION')
8
+ require_asset "jquery-ui"
9
+ elsif Jquery.const_defined? 'Ui'
10
+ jquery_ui_prefix = Jquery::Ui::Rails::VERSION < '5.0.0' ? 'jquery.ui.' : 'jquery-ui/'
11
+ jquery_ui_widgets_prefix = Jquery::Ui::Rails::VERSION >= '6.0.0' ? 'widgets/' : ''
12
+ require_asset "#{jquery_ui_prefix}core"
13
+ require_asset "#{jquery_ui_prefix}effect"
14
+ require_asset "#{jquery_ui_prefix}effects/effect-highlight" if Jquery::Ui::Rails::VERSION >= '6.0.0'
15
+ require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}sortable"
16
+ require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}draggable"
17
+ require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}droppable"
18
+ require_asset "#{jquery_ui_prefix}#{jquery_ui_widgets_prefix}datepicker"
19
+ end
18
20
  end
19
21
  if ActiveScaffold.jquery_ui_included?
20
22
  require_asset "jquery-ui-timepicker-addon"
@@ -1,10 +1,12 @@
1
- <% if Jquery::Rails.const_defined? 'JQUERY_UI_VERSION' %>
2
- <% require_asset "jquery-ui" %>
3
- <% elsif Jquery.const_defined? 'Ui' %>
4
- <% if Jquery::Ui::Rails::VERSION < '5.0.0' %>
5
- <% require_asset "jquery.ui.datepicker" %>
6
- <% else %>
7
- <% require_asset "jquery-ui/datepicker" %>
1
+ <% if Object.const_defined?('Jquery') %>
2
+ <% if Jquery.const_defined?('Rails') && Jquery::Rails.const_defined?('JQUERY_UI_VERSION') %>
3
+ <% require_asset "jquery-ui" %>
4
+ <% elsif Jquery.const_defined? 'Ui' %>
5
+ <% if Jquery::Ui::Rails::VERSION < '5.0.0' %>
6
+ <% require_asset "jquery.ui.datepicker" %>
7
+ <% else %>
8
+ <% require_asset "jquery-ui/datepicker" %>
9
+ <% end %>
8
10
  <% end %>
9
11
  <% end %>
10
12
  <% require_asset "jquery-ui-theme" if ActiveScaffold.jquery_ui_included? %>
@@ -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
@@ -146,7 +149,7 @@ module ActiveScaffold
146
149
  conditions.concat options[:conditions][1..-1] if options[:conditions]
147
150
  if column.association&.polymorphic?
148
151
  conditions[0] << " AND #{column.quoted_foreign_type} = ?"
149
- conditions << relation.name
152
+ conditions << relation.base_class.sti_name
150
153
  end
151
154
  conditions
152
155
  end
@@ -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,8 +2,8 @@ module ActiveScaffold
2
2
  module Version
3
3
  MAJOR = 3
4
4
  MINOR = 7
5
- PATCH = 3
6
- FIX = 1
5
+ PATCH = 5
6
+ FIX = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, FIX].compact.join('.')
9
9
  end
@@ -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.3.1
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-08 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