Module: ActiveScaffold::Helpers::SearchColumnHelpers

Included in:
ViewHelpers
Defined in:
lib/active_scaffold/helpers/search_column_helpers.rb

Overview

Helpers that assist with the rendering of a Form Column

Instance Method Summary collapse

Instance Method Details

#active_scaffold_group_columnObject

[View source]

156
157
158
159
160
161
162
163
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 156

def active_scaffold_group_column
  return if active_scaffold_config.field_search.group_options.blank?
  @_active_scaffold_group_column ||= begin
    column = ActiveScaffold::DataStructures::Column.new(:active_scaffold_group, active_scaffold_config.model)
    column.label = :group_by
    column
  end
end

#active_scaffold_group_search_column(record, options) ⇒ Object

[View source]

145
146
147
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 145

def active_scaffold_group_search_column(record, options)
  select_tag 'search[active_scaffold_group]', options_for_select(active_scaffold_group_search_options, selected: field_search_params['active_scaffold_group'])
end

#active_scaffold_group_search_optionsObject

[View source]

149
150
151
152
153
154
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 149

def active_scaffold_group_search_options
  options = active_scaffold_config.field_search.group_options.collect do |text, value|
    active_scaffold_translated_option(active_scaffold_group_column, text, value)
  end
  [[as_(:no_group), '']].concat options
end

#active_scaffold_search_boolean(column, options) ⇒ Object Also known as: active_scaffold_search_checkbox

we can't use active_scaffold_input_boolean because we need to have a nil value even when column can't be null to decide whether search for this field or not

[View source]

134
135
136
137
138
139
140
141
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 134

def active_scaffold_search_boolean(column, options)
  select_options = []
  select_options << [as_(:_select_), nil]
  select_options << [as_(:true), true] # rubocop:disable Lint/BooleanSymbol
  select_options << [as_(:false), false] # rubocop:disable Lint/BooleanSymbol

  select_tag(options[:name], options_for_select(select_options, ActiveScaffold::Core.column_type_cast(options[:value], column.column)), :id => options[:id])
end

#active_scaffold_search_date(column, options) ⇒ Object

[View source]

267
268
269
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 267

def active_scaffold_search_date(column, options)
  active_scaffold_search_datetime(column, options.merge!(:discard_time => true))
end

#active_scaffold_search_datetime(column, options) ⇒ Object Also known as: active_scaffold_search_timestamp

[View source]

243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 243

def active_scaffold_search_datetime(column, options)
  _, from_value, to_value = field_search_params_range_values(column)
  options = column.options.merge(options)
  type = "#{'date' unless options[:discard_date]}#{'time' unless options[:discard_time]}"
  use_select = options.delete(:use_select)
  from_name = "#{options[:name]}[from]"
  to_name = "#{options[:name]}[to]"
  if use_select
    helper = "select_#{type}"
    fields = [
      send(helper, field_search_datetime_value(from_value), options.reverse_merge(include_blank: true, prefix: from_name)),
      send(helper, field_search_datetime_value(to_value), options.reverse_merge(include_blank: true, prefix: to_name))
    ]
  else
    helper = "#{type}#{'_local' if type == 'datetime'}_field_tag"
    fields = [
      send(helper, from_name, field_search_datetime_value(from_value), options.except(:name, :object).merge(id: "#{options[:id]}_from")),
      send(helper, to_name, field_search_datetime_value(to_value), options.except(:name, :object).merge(id: "#{options[:id]}_to"))
    ]
  end

  safe_join fields, ' - '
end

#active_scaffold_search_decimal(column, options) ⇒ Object Also known as: active_scaffold_search_float

[View source]

234
235
236
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 234

def active_scaffold_search_decimal(column, options)
  active_scaffold_search_range(column, options, :number_field_tag, step: :any)
end

#active_scaffold_search_for(column, options = nil) ⇒ Object

This method decides which input to use for the given column. It does not do any rendering. It only decides which method is responsible for rendering.

[View source]

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 7

def active_scaffold_search_for(column, options = nil)
  options ||= active_scaffold_search_options(column)
  record = options[:object]
  if column.delegated_association
    record = record.send(column.delegated_association.name) || column.active_record_class.new
    options[:object] = record
  end

  # first, check if the dev has created an override for this specific field for search
  if (method = override_search_field(column))
    send(method, record, options)

  # second, check if the dev has specified a valid search_ui for this column, using specific ui for searches
  elsif column.search_ui && (method = override_search(column.search_ui))
    send(method, column, options)

  # third, check if the dev has specified a valid search_ui for this column, using generic ui for forms
  elsif column.search_ui && (method = override_input(column.search_ui))
    send(method, column, options)

  # fourth, check if the dev has created an override for this specific field
  elsif (method = override_form_field(column))
    send(method, record, options)

  # fallback: we get to make the decision
  elsif column.association || column.virtual?
    active_scaffold_search_text(column, options)

  elsif (method = override_search(column.column.type))
    # if we (or someone else) have created a custom render option for the column type, use that
    send(method, column, options)

  elsif (method = override_input(column.column.type))
    # if we (or someone else) have created a custom render option for the column type, use that
    send(method, column, options)

  else # final ultimate fallback: use rails' generic input method
    # for textual fields we pass different options
    text_types = %i[text string integer float decimal]
    options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
    text_field(:record, column.name, options.merge(column.options))
  end
rescue StandardError => e
  logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
  raise e
end

#active_scaffold_search_integer(column, options) ⇒ Object

[View source]

230
231
232
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 230

def active_scaffold_search_integer(column, options)
  active_scaffold_search_range(column, options, :number_field_tag, step: '1')
end

#active_scaffold_search_multi_select(column, options) ⇒ Object

Search input methods

[View source]

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 75

def active_scaffold_search_multi_select(column, options)
  record = options.delete(:object)
  associated = options.delete :value
  associated = [associated].compact unless associated.is_a? Array

  if column.association
    associated.collect!(&:to_i)
    method = column.options[:label_method] || :to_label
    select_options = sorted_association_options_find(column.association, nil, record).collect do |r|
      [r.send(method), r.id]
    end
  else
    select_options = column.options[:options].collect do |text, value|
      active_scaffold_translated_option(column, text, value)
    end
  end
  return as_(:no_options) if select_options.empty?

  active_scaffold_checkbox_list(column, select_options, associated, options)
end

#active_scaffold_search_null(column, options) ⇒ Object

[View source]

165
166
167
168
169
170
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 165

def active_scaffold_search_null(column, options)
  select_options = []
  select_options << [as_(:_select_), nil]
  select_options.concat(ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] })
  select_tag(options[:name], options_for_select(select_options, options[:value]), :id => options[:id])
end

#active_scaffold_search_options(column) ⇒ Object

the standard active scaffold options used for class, name and scope

[View source]

55
56
57
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 55

def active_scaffold_search_options(column)
  {:name => "search[#{column.name}]", :class => "#{column.name}-input", :id => "search_#{column.name}", :value => field_search_params[column.name.to_s]}
end

#active_scaffold_search_range(column, options, input_method = :text_field_tag, input_options = {}) ⇒ Object Also known as: active_scaffold_search_string

[View source]

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 203

def active_scaffold_search_range(column, options, input_method = :text_field_tag, input_options = {})
  opt_value, from_value, to_value = field_search_params_range_values(column)

  select_options = active_scaffold_search_range_comparator_options(column)
  text_field_size = active_scaffold_search_range_string?(column) ? 15 : 10
  opt_value ||= select_options[0][1]

  from_value = controller.class.condition_value_for_numeric(column, from_value)
  to_value = controller.class.condition_value_for_numeric(column, to_value)
  from_value = format_number_value(from_value, column.options) if from_value.is_a?(Numeric)
  to_value = format_number_value(to_value, column.options) if to_value.is_a?(Numeric)
  html = select_tag("#{options[:name]}[opt]", options_for_select(select_options, opt_value),
                    :id => "#{options[:id]}_opt", :class => 'as_search_range_option')
  from_options = active_scaffold_input_text_options(input_options.merge(:id => options[:id], :size => text_field_size))
  to_options = from_options.merge(:id => "#{options[:id]}_to")
  html << ('span', :id => "#{options[:id]}_numeric", :style => ActiveScaffold::Finder::NULL_COMPARATORS.include?(opt_value) ? 'display: none' : nil) do
    send(input_method, "#{options[:name]}[from]", from_value, input_options) <<
      (
        :span,
        safe_join([' - ', send(input_method, "#{options[:name]}[to]", to_value, to_options)]),
        :id => "#{options[:id]}_between", :class => 'as_search_range_between', :style => ('display: none' unless opt_value == 'BETWEEN')
      )
  end
   :span, html, :class => 'search_range'
end

#active_scaffold_search_range_comparator_options(column) ⇒ Object

[View source]

182
183
184
185
186
187
188
189
190
191
192
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 182

def active_scaffold_search_range_comparator_options(column)
  select_options = ActiveScaffold::Finder::NUMERIC_COMPARATORS.collect { |comp| [as_(comp.downcase.to_sym), comp] }
  if active_scaffold_search_range_string?(column)
    comparators = ActiveScaffold::Finder::STRING_COMPARATORS.collect { |title, comp| [as_(title), comp] }
    select_options.unshift(*comparators)
  end
  if include_null_comparators? column
    select_options.concat(ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] })
  end
  select_options
end

#active_scaffold_search_range_string?(column) ⇒ Boolean

Returns:

  • (Boolean)
[View source]

178
179
180
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 178

def active_scaffold_search_range_string?(column)
  column.text? || column.search_ui == :string
end

#active_scaffold_search_select(column, html_options, options = {}) ⇒ Object

[View source]

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 96

def active_scaffold_search_select(column, html_options, options = {})
  record = html_options.delete(:object)
  associated = html_options.delete :value
  if column.association
    associated = associated.is_a?(Array) ? associated.map(&:to_i) : associated.to_i unless associated.nil?
    method = column.association.belongs_to? ? column.association.foreign_key : column.name
    select_options = sorted_association_options_find(column.association, false, record)
  else
    method = column.name
    select_options = active_scaffold_enum_options(column, record).collect do |text, value|
      active_scaffold_translated_option(column, text, value)
    end
  end

  options = options.merge(:selected => associated).merge column.options
  html_options.merge! column.options[:html_options] || {}
  if html_options[:multiple]
    active_scaffold_select_name_with_multiple html_options
  else
    options[:include_blank] ||= as_(:_select_)
    active_scaffold_translate_select_options(options)
  end

  if (optgroup = options.delete(:optgroup))
    select(:record, method, active_scaffold_grouped_options(column, select_options, optgroup), options, html_options)
  elsif column.association
    collection_select(:record, method, select_options, :id, column.options[:label_method] || :to_label, options, html_options)
  else
    select(:record, method, select_options, options, html_options)
  end
end

#active_scaffold_search_text(column, options) ⇒ Object

[View source]

128
129
130
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 128

def active_scaffold_search_text(column, options)
  text_field :record, column.name, active_scaffold_input_text_options(options)
end

#active_scaffold_search_time(column, options) ⇒ Object

[View source]

271
272
273
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 271

def active_scaffold_search_time(column, options)
  active_scaffold_search_datetime(column, options.merge!(:discard_date => true))
end

#field_search_datetime_value(value) ⇒ Object

[View source]

239
240
241
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 239

def field_search_datetime_value(value)
  Time.zone.local(value[:year].to_i, value[:month].to_i, value[:day].to_i, value[:hour].to_i, value[:minute].to_i, value[:second].to_i) unless value.nil? || value[:year].blank?
end

#field_search_params_range_values(column) ⇒ Object

[View source]

172
173
174
175
176
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 172

def field_search_params_range_values(column)
  values = field_search_params[column.name.to_s]
  return nil unless values.is_a? Hash
  [values['opt'], values['from'].presence, values['to'].presence]
end

#include_null_comparators?(column) ⇒ Boolean

Returns:

  • (Boolean)
[View source]

194
195
196
197
198
199
200
201
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 194

def include_null_comparators?(column)
  return column.options[:null_comparators] if column.options.key? :null_comparators
  if column.association
    !column.association.belongs_to? || active_scaffold_config.columns[column.association.foreign_key].column&.null
  else
    column.column&.null
  end
end

#override_search(form_ui) ⇒ Object

the naming convention for overriding search input types with helpers

[View source]

289
290
291
292
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 289

def override_search(form_ui)
  method = "active_scaffold_search_#{form_ui}"
  method if respond_to? method
end

#override_search_field(column) ⇒ Object

[View source]

284
285
286
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 284

def override_search_field(column)
  override_helper column, 'search_column'
end

#search_attribute(column, record) ⇒ Object

[View source]

59
60
61
62
63
64
65
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 59

def search_attribute(column, record)
  column_options = active_scaffold_search_options(column).merge(:object => record)
   :dl do
    (:dt, label_tag(search_label_for(column, column_options), search_column_label(column, record))) <<
      (:dd, active_scaffold_search_for(column, column_options))
  end
end

#search_column_label(column, record) ⇒ Object

Search column override signatures

[View source]

280
281
282
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 280

def search_column_label(column, record)
  column.label
end

#search_label_for(column, options) ⇒ Object

[View source]

67
68
69
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 67

def search_label_for(column, options)
  options[:id] unless %i[range integer decimal float string date_picker datetime_picker calendar_date_select].include? column.search_ui
end

#searched_by?(column) ⇒ Boolean

Returns:

  • (Boolean)
[View source]

312
313
314
315
316
317
318
319
320
321
322
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 312

def searched_by?(column)
  value = field_search_params[column.name.to_s]
  case value
  when Hash
    value['from'].present?
  when String
    value.present?
  else
    false
  end
end

#visibles_and_hiddens(search_config) ⇒ Object

[View source]

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/active_scaffold/helpers/search_column_helpers.rb', line 294

def visibles_and_hiddens(search_config)
  visibles = []
  hiddens = []
  search_config.columns.each_column do |column|
    next unless column.search_sql
    if search_config.optional_columns.include?(column.name) && !searched_by?(column)
      hiddens << column
    else
      visibles << column
    end
  end
  if active_scaffold_group_column
    columns = grouped_search? || search_config.optional_columns.empty? ? visibles : hiddens
    columns << active_scaffold_group_column
  end
  [visibles, hiddens]
end