How to Handle Blank Values and Edge Cases in Ransack Searches
Ransack automatically strips blank parameters during Search object initialization and provides a dedicated _blank predicate to explicitly query for NULL or empty columns, preventing unwanted SQL generation.
The activerecord-hackery/ransack library includes sophisticated logic to handle blank values and other edge cases in Ransack searches across its node hierarchy. Understanding these mechanisms ensures your filtering interfaces degrade gracefully when users submit empty forms, while still allowing explicit queries for missing data.
How Ransack Automatically Removes Blank Parameters
When you initialize a Ransack::Search object, the library immediately sanitizes the input hash to eliminate values that would generate meaningless SQL predicates.
Parameter Sanitization in Search Objects
In lib/ransack/search.rb (lines 27–30), the constructor duplicates your parameters and strips whitespace if the strip_whitespace option is enabled (the default). It then rejects any key-value pair where the value is completely blank using the guard:
[ *v ].all?{ |i| i.blank? && i != false }
This expression wraps single values in an array and verifies that every element is blank, while explicitly preserving false values through the i != false check. Consequently, empty strings, nil, and arrays containing only blanks are removed before the Search object builds its Arel tree.
Preserving Boolean False Values
The blank-detection logic specifically guards against removing false values. Because the validation block checks i != false, an explicit false in your search parameters—critical for boolean column filtering—is retained and passed through to the predicate builders.
Using the _blank Predicate for NULL Queries
Beyond silently dropping blanks, Ransack exposes a dedicated predicate to explicitly search for empty or NULL columns without writing custom SQL.
The Blank Predicate Implementation
In lib/ransack/constants.rb (lines 136–142), Ransack registers a boolean predicate named blank. Its Arel mapping uses EQ_ANY when the supplied boolean is truthy and NOT_EQ_ALL when falsy, allowing you to query:
field_blank: true— matches records where the column is NULL or empty stringfield_blank: false— matches records where the column is NOT NULL and not empty
The predicate validates input against BOOLEAN_VALUES.include?, ensuring only true or false are accepted.
Handling Edge Cases Across Node Types
Ransack's blank-handling strategy extends through its node hierarchy to prevent malformed SQL at every stage of query construction.
Multi-Parameter Date Attributes
Rails date_select helpers send parameters like birthday(1i), birthday(2i), and birthday(3i). In lib/ransack/search.rb (lines 63–86), the collapse_multiparameter_attributes! method detects these segmented keys. If any component is blank, the method intelligently drops those components or returns nil for the entire date, preventing partial date construction that would otherwise yield invalid SQL comparisons.
Empty Arrays and IN Clauses
When you pass an empty array to a predicate like ids_in: [], Ransack prevents the database error that would result from IN () syntax. Both lib/ransack/nodes/grouping.rb (line 165) and lib/ransack/nodes/condition.rb (line 281) filter their sub-elements by rejecting blank values:
.reject { |e| e[1].blank? }
This pruning occurs before the Arel tree generates SQL, silently removing the condition rather than executing an empty set comparison.
Sort Node Protection
The sorting mechanism in lib/ransack/nodes/sort.rb (line 11) includes an early return if the raw sort string is blank. This prevents the generation of empty ORDER BY clauses that would cause SQL syntax errors when users submit sort forms without selecting a column.
Value Node Casting
In lib/ransack/nodes/value.rb (line 5), the Value node delegates blank? and present? to the underlying Ruby object. This delegation allows casting helpers like cast_to_integer and cast_to_float to recognize blank inputs and return nil appropriately, ensuring type coercion does not accidentally convert empty strings to zero or other unintended default values.
Practical Code Examples
Filtering for Blank Columns
Use the _blank predicate to find records with empty or NULL email addresses:
User.ransack(email_blank: true).result
Internally, this invokes the blank predicate defined in constants.rb, generating SQL that checks for both NULL and empty string conditions using the EQ_ANY mapping.
Automatic Parameter Cleaning
Blank values are stripped automatically during Search initialization:
params = { name_cont: ' ', age_eq: '' }
search = User.ransack(params) # Empty values removed at lines 27-30 of search.rb
search.result # Returns all users, no WHERE clause added
The whitespace-only string ' ' is stripped to '' and subsequently removed, while the empty string for age_eq is discarded entirely.
Excluding Blank Values
To find users with a populated first name and specific age:
User.ransack(first_name_blank: false, age_eq: 30).result
This generates WHERE "users"."first_name" IS NOT NULL AND "users"."first_name" <> '' via the NOT_EQ_ALL mapping defined in the blank predicate.
Handling Empty Arrays
Passing an empty array does not raise a database error:
User.ransack(ids_in: []).result # Condition pruned, returns all records
The blank detection in search.rb and the grouping/condition pruning logic ensure no IN () syntax error reaches the database.
Multi-Parameter Date Handling
When date components are partially blank, Ransack collapses them safely:
# birthday(2i) and birthday(3i) are empty
User.ransack(birthday(1i): '2024', birthday(2i): '', birthday(3i): '')
# Results in proper Date object construction or nil, not malformed SQL
The collapse_multiparameter_attributes! routine handles the blank middle and day components without constructing invalid date ranges.
Summary
- Automatic sanitization: In
lib/ransack/search.rb, blank parameters (empty strings, nil, whitespace) are stripped at initialization to prevent emptyWHEREclauses. - Boolean preservation: The blank detection logic explicitly keeps
falsevalues, ensuring boolean filters generate correct SQL predicates. - Explicit blank queries: Use the
_blankpredicate (defined inlib/ransack/constants.rb) to query for NULL or empty columns usingEQ_ANYandNOT_EQ_ALLArel mappings. - Empty array safety:
lib/ransack/nodes/grouping.rbandcondition.rbprune blank conditions, preventing syntax errors from emptyIN ()clauses. - Date parameter handling: The
collapse_multiparameter_attributes!method insearch.rbsafely manages partial date inputs from Rails form helpers.
Frequently Asked Questions
Does Ransack remove empty strings from search parameters?
Yes. In lib/ransack/search.rb (lines 27–30), Ransack duplicates and inspects all parameters, removing any where the value is blank according to the [ *v ].all?{ |i| i.blank? && i != false } check. This includes empty strings, nil, and whitespace-only strings when strip_whitespace is enabled.
How do I search for records where a column is NULL or empty?
Use the _blank predicate registered in lib/ransack/constants.rb (lines 136–142). Pass field_blank: true to find records where the column is NULL or an empty string, or field_blank: false to exclude them. This generates the appropriate EQ_ANY or NOT_EQ_ALL Arel constraints.
Will Ransack ignore false values in my search parameters?
No. The blank detection logic specifically guards against removing false through the i != false condition in the validation block. This ensures that boolean searches like active_eq: false are preserved and generate the correct SQL predicates.
How does Ransack prevent empty IN clause errors?
When you pass an empty array to a predicate like ids_in: [], Ransack prunes this condition in lib/ransack/nodes/grouping.rb (line 165) and lib/ransack/nodes/condition.rb (line 281) by rejecting blank sub-elements. This prevents the generation of invalid IN () SQL syntax.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →