Module: Plutonium::Resource::Controllers::Typeahead
- Extended by:
- ActiveSupport::Concern
- Included in:
- Plutonium::Resource::Controller
- Defined in:
- lib/plutonium/resource/controllers/typeahead.rb
Overview
Backend dispatch for typeahead/autocomplete queries against
resource form inputs and index filter inputs. Auto-mounted on
every Plutonium resource via the interactive_resource_actions
routing concern (see Plutonium::Routing::MapperExtensions).
The controller resolves what to query directly from the input definition + the model's association reflection — no widget indirection. Two source kinds are supported:
1. Static `choices: [...]` — case-insensitive substring filter.
2. Association — either `association_class:` set on the input,
or inferred from `resource_class.reflect_on_association(name)`.
Association queries route through the associated resource's
policy.relation_scope so users only see records they can read.
Constant Summary collapse
- TYPEAHEAD_LIMIT =
50- FALLBACK_SEARCH_COLUMNS =
Priority list tried when the input doesn't tell us which column carries its label. Aligns with what
to_labelusually wraps. Used only as a last resort. %w[name title label slug display_name email].freeze
- LIKE_ESCAPE_CHAR =
Escapes the SQL LIKE wildcards
%and_(plus the escape char itself) so a user searching for "100%" doesn't match everything. The literal!is used as the ESCAPE character — unambiguous across sqlite/postgres/mysql, no backslash-quoting surprises. "!"
Class Method Summary collapse
- .escape_like(value) ⇒ Object
-
.searchable_column_for(klass, label_method: nil) ⇒ Object
Returns the column to LIKE against when no
searchblock is defined.
Instance Method Summary collapse
-
#typeahead_filter ⇒ Object
GET /
/typeahead/filter/:name?q=... -
#typeahead_input ⇒ Object
GET /
/typeahead/input/:name?q=...
Class Method Details
.escape_like(value) ⇒ Object
60 61 62 |
# File 'lib/plutonium/resource/controllers/typeahead.rb', line 60 def self.escape_like(value) value.to_s.gsub(/[!%_]/) { |c| "#{LIKE_ESCAPE_CHAR}#{c}" } end |
.searchable_column_for(klass, label_method: nil) ⇒ Object
Returns the column to LIKE against when no search block is
defined. Used by both the server (to build the WHERE clause)
and the input component (to decide whether to attach the
typeahead URL).
Resolution order:
- The input's
label_methodif it names a real column (soinput :user, label_method: :emailjust works). - The first match from FALLBACK_SEARCH_COLUMNS.
- nil — no usable column, server returns unfiltered.
The fallback is fine for moderate tables but uses a leading-
wildcard LIKE which can't be served by a b-tree index. For
large tables, declare a search block that uses a trigram or
full-text index instead.
46 47 48 49 50 51 52 |
# File 'lib/plutonium/resource/controllers/typeahead.rb', line 46 def self.searchable_column_for(klass, label_method: nil) cols = klass.column_names if label_method && cols.include?(label_method.to_s) return label_method.to_s end FALLBACK_SEARCH_COLUMNS.find { |c| cols.include?(c) } end |
Instance Method Details
#typeahead_filter ⇒ Object
GET /
87 88 89 90 91 92 93 94 95 |
# File 'lib/plutonium/resource/controllers/typeahead.rb', line 87 def typeahead_filter filter = current_query_object.filter_definitions[params[:name].to_sym] return head(:not_found) unless filter defn = filter.defined_inputs[:value] return head(:not_found) unless defn render_typeahead_response(defn, params[:name].to_sym) end |
#typeahead_input ⇒ Object
GET /
73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/plutonium/resource/controllers/typeahead.rb', line 73 def typeahead_input field_name = params[:name].to_sym defn = current_definition.defined_inputs[field_name] # Inputs are often inferred from the model (no explicit # `input :foo` in the definition). Accept the request when the # field name maps to a real association even without an entry. unless defn || resource_class.reflect_on_association(field_name) return head(:not_found) end render_typeahead_response(defn || {}, field_name) end |