Module: ElaineCrud::SearchHelper

Defined in:
app/helpers/elaine_crud/search_helper.rb

Overview

Helper methods for rendering search and filter UI components

Instance Method Summary collapse

Instance Method Details

#get_filter_options(field_name, config) ⇒ Array

Get filter options for a field

Parameters:

  • field_name (Symbol)

    Field name

  • config (FieldConfiguration, nil)

    Field configuration

Returns:

  • (Array)

    Array of [display, value] pairs for select options



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'app/helpers/elaine_crud/search_helper.rb', line 110

def get_filter_options(field_name, config)
  # If field has configured options, use those
  if config&.has_options?
    options = config.options
    # Handle both array and hash formats
    if options.is_a?(Hash)
      options.to_a
    else
      options.map { |opt| [opt, opt] }
    end
  # If it's a foreign key, get options from related model
  elsif config&.has_foreign_key?
    config.foreign_key_options(controller)
  # Otherwise, get distinct values from database
  else
    crud_model.distinct.pluck(field_name).compact.sort.map { |v| [v, v] }
  end
rescue => e
  Rails.logger.error "ElaineCrud: Error getting filter options for #{field_name}: #{e.message}"
  []
end

#render_boolean_filter(field_name, config) ⇒ String

Render a boolean filter (Yes/No/All)

Parameters:

  • field_name (Symbol)

    Field name

  • config (FieldConfiguration, nil)

    Field configuration

Returns:

  • (String)

    HTML for boolean filter



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/helpers/elaine_crud/search_helper.rb', line 51

def render_boolean_filter(field_name, config)
  (:div, class: "flex flex-col") do
    label = (:label, config&.title || field_name.to_s.humanize,
                       class: "text-sm font-medium text-gray-700 mb-1")

    select = select_tag "filter[#{field_name}]",
                       options_for_select([["All", ""], ["Yes", "true"], ["No", "false"]],
                                        @active_filters[field_name.to_s]),
                       class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"

    label + select
  end
end

#render_date_range_filter(field_name, config) ⇒ String

Render a date range filter (from/to inputs)

Parameters:

  • field_name (Symbol)

    Field name

  • config (FieldConfiguration, nil)

    Field configuration

Returns:

  • (String)

    HTML for date range filter



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'app/helpers/elaine_crud/search_helper.rb', line 69

def render_date_range_filter(field_name, config)
  (:div, class: "flex flex-col") do
    label = (:label, config&.title || field_name.to_s.humanize,
                       class: "text-sm font-medium text-gray-700 mb-1")

    from_field = date_field_tag "filter[#{field_name}_from]",
                                 @active_filters["#{field_name}_from"],
                                 placeholder: "From",
                                 class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 text-sm"

    to_field = date_field_tag "filter[#{field_name}_to]",
                               @active_filters["#{field_name}_to"],
                               placeholder: "To",
                               class: "block w-full mt-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 text-sm"

    label + from_field + to_field
  end
end

#render_filter_field(field_info) ⇒ String

Render a filter field based on its type

Parameters:

  • field_info (Hash)

    Field information with name, type, and config

Returns:

  • (String)

    HTML for the filter field



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'app/helpers/elaine_crud/search_helper.rb', line 9

def render_filter_field(field_info)
  field_name = field_info[:name]
  filter_type = field_info[:type]
  config = field_info[:config]

  case filter_type
  when :select
    render_select_filter(field_name, config)
  when :boolean
    render_boolean_filter(field_name, config)
  when :date_range
    render_date_range_filter(field_name, config)
  when :text
    render_text_filter(field_name, config)
  else
    render_text_filter(field_name, config)
  end
end

#render_select_filter(field_name, config) ⇒ String

Render a select dropdown filter

Parameters:

  • field_name (Symbol)

    Field name

  • config (FieldConfiguration, nil)

    Field configuration

Returns:

  • (String)

    HTML for select filter



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'app/helpers/elaine_crud/search_helper.rb', line 32

def render_select_filter(field_name, config)
  (:div, class: "flex flex-col") do
    label = (:label, config&.title || field_name.to_s.humanize,
                       class: "text-sm font-medium text-gray-700 mb-1")

    options = get_filter_options(field_name, config)
    select = select_tag "filter[#{field_name}]",
                       options_for_select(options, @active_filters[field_name.to_s]),
                       include_blank: "All",
                       class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"

    label + select
  end
end

#render_text_filter(field_name, config) ⇒ String

Render a text input filter

Parameters:

  • field_name (Symbol)

    Field name

  • config (FieldConfiguration, nil)

    Field configuration

Returns:

  • (String)

    HTML for text filter



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'app/helpers/elaine_crud/search_helper.rb', line 92

def render_text_filter(field_name, config)
  (:div, class: "flex flex-col") do
    label = (:label, config&.title || field_name.to_s.humanize,
                       class: "text-sm font-medium text-gray-700 mb-1")

    input = text_field_tag "filter[#{field_name}]",
                          @active_filters[field_name.to_s],
                          placeholder: "Filter by #{(config&.title || field_name.to_s.humanize).downcase}",
                          class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"

    label + input
  end
end