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 string
  • field_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 empty WHERE clauses.
  • Boolean preservation: The blank detection logic explicitly keeps false values, ensuring boolean filters generate correct SQL predicates.
  • Explicit blank queries: Use the _blank predicate (defined in lib/ransack/constants.rb) to query for NULL or empty columns using EQ_ANY and NOT_EQ_ALL Arel mappings.
  • Empty array safety: lib/ransack/nodes/grouping.rb and condition.rb prune blank conditions, preventing syntax errors from empty IN () clauses.
  • Date parameter handling: The collapse_multiparameter_attributes! method in search.rb safely 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →