activerecord-hackery/ransack · error · InvalidSearchError
Invalid search term #{key}
Error message
Invalid search term #{key} What it means
Search#build iterates every key of the q params hash. A key must be 's'/'sorts', a whitelisted ransackable scope, or an attribute method recognized by the context (attribute + predicate over a searchable association). Otherwise, when unknown conditions are not ignored — Model.ransack! sets ignore_unknown_conditions: false per search, and the global config can too — Ransack raises InvalidSearchError with 'Invalid search term <key>'.
Source
Thrown at lib/ransack/search.rb:57
@sorts ||= []
@ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true
build(params.with_indifferent_access)
end
def result(opts = {})
@context.evaluate(self, opts)
end
def build(params)
collapse_multiparameter_attributes!(params).each do |key, value|
if ['s'.freeze, 'sorts'.freeze].freeze.include?(key)
send("#{key}=", value)
elsif @context.ransackable_scope?(key, @context.object)
add_scope(key, value)
elsif base.attribute_method?(key)
base.send("#{key}=", value)
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
raise InvalidSearchError, "Invalid search term #{key}"
end
end
self
end
def sorts=(args)
case args
when Array
args.each do |sort|
if sort.kind_of? Hash
sort = Nodes::Sort.new(@context).build(sort)
else
sort = Nodes::Sort.extract(@context, sort)
end
self.sorts << sort if sort
end
when Hash
args.each do |index, attrs|View on GitHub (pinned to e82f6bab39)
Solutions
- Add the attribute to the model allowlist: def self.ransackable_attributes(auth_object = nil); %w[name ... full_name] ... end
- For scopes, add the scope name to ransackable_scopes whitelist (as symbols) and define the scope
- Use non-strict Model.ransack(params[:q]) instead of ransack! so unknown terms are silently dropped (default ignore_unknown_conditions: true)
- Rescue Ransack::InvalidSearchError in the controller, notify the user, and re-render with a clean search
Example fix
# before
# params: q => { "full_name_eq" => "Alice" }
Person.ransack!(params[:q])
# => Ransack::InvalidSearchError: Invalid search term full_name_eq
# after
class Person < ApplicationRecord
def self.ransackable_attributes(auth_object = nil)
%w[name full_name created_at]
end
end
Person.ransack!(params[:q]) Defensive patterns
Strategy: try-catch
Validate before calling
# reject keys that are neither sorts, whitelisted scopes, nor searchable attributes
ALLOWED_SCOPES = %i[active].freeze
def strict_q_params(raw, klass)
raw.select do |key, _|
next true if %w[s sorts].include?(key)
next true if klass.ransackable_scopes.map(&:to_s).include?(key)
klass.ransackable_attributes.any? do |a|
key.start_with?(a) && key != a # has a predicate suffix
end
end
end
@q = Person.ransack!(strict_q_params(params[:q], Person)) Type guard
def known_search_term?(key, klass)
%w[s sorts].include?(key) ||
klass.method_defined?(nil) ||
klass.ransackable_attributes.any? { |a| key.to_s.start_with?(a + '_') } ||
klass.ransackable_scopes.any? { |s| s.to_s == key }
end Try / catch
begin
@q = Person.ransack!(params[:q])
rescue Ransack::InvalidSearchError => e
Rails.logger.warn("Rejected search term: #{e.message}")
@q = Person.ransack # empty search, user re-enters filters
end Prevention
- Keep ransackable_attributes/ransackable_scopes allowlists in sync with every form field you ship
- Use ransack! only on internal endpoints; for public endpoints use ransack and validate params anyway
- Scope the q param in Strong Parameters (permit specific q keys when feasible) so stray fields never reach the search
When it happens
Trigger: Person.ransack!(params[:q]) where params include q[full_name_eq]=x but full_name is not in Person.ransackable_attributes; q[enabled]=true where enabled is neither attribute-with-predicate nor whitelisted scope; stray keys like q[commit] or q[utf8] leaking in; an attribute on an association whose ransackable_associations whitelist excludes it.
Common situations: Adopting the strict ransack! convention after a security review; adding new searchable columns or ransackers but forgetting to update ransackable_attributes/ransackable_scopes allowlists; forms that submit extra fields (submit buttons, hidden CSRF-derived keys) inside the q namespace; users hand-editing URLs.
Related errors
- No valid predicate for #{key}
- Invalid argument (#{args.class}) supplied to sorts=
- #{type} cannot be converted to an ARel join type
- #{value} cannot be converted to a Class
- Don't know how to klassify #{obj}
AI-assisted analysis of activerecord-hackery/ransack@e82f6bab39 (2026-08-21).
Data as JSON: /api/errors/933539b2d46cefb9.
Report an issue: GitHub.