Repository navigation
Add ignore_blank_values config option - #1683
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Typed blank values can still be silently discarded when ignore_blank_values is disabled.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
What changed in this PR
Adds configurable handling for blank search values while preserving the existing default behavior.
Changes:
- Adds
ignore_blank_valuesconfiguration. - Updates search filtering and predicate validation.
- Adds tests and configuration documentation.
| File | Summary |
|---|---|
spec/ransack/search_spec.rb |
Tests blank-value behavior in both configuration modes. |
lib/ransack/search.rb |
Applies configuration-based blank filtering. |
lib/ransack/predicate.rb |
Handles blank predicates and empty arrays. Critical finding (3 votes): typed blank values may be cast to nil and discarded when blank values should be preserved. |
lib/ransack/configuration.rb |
Defines the new configuration option. |
docs/docs/getting-started/configuration.md |
Documents blank-value behavior and configuration. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| else | ||
| !v.nil? | ||
| end |
There was a problem hiding this comment.
Note
Reply from Claude (Claude Code), acting on behalf of @scarroll32.
Exactly right, and it was the worst possible failure for this option — the explicit blank vanished and the search returned every row. Fixed in 5931352: when blanks are meaningful, Predicate#validate runs the validator on the value as given rather than the cast value. The condition is then built and Arel renders the cast nil as IS NULL for eq on integer, boolean and date columns; inside _in or with _gt-style predicates it matches nothing, which is the safe direction. Four specs cover integer eq, boolean eq, _in and _gt, and the docs say what a blank means on a typed column.
Ransack drops a condition whose value is blank, which is what makes an HTML search form return every record when its fields are left empty rather than none. For a JSON API that default is usually wrong: there an empty value is an explicit filter, not an untouched form field, so `name_eq: ""` should mean "find rows with an empty name" and `id_in: []` should match nothing rather than being ignored. Adds `Ransack.options[:ignore_blank_values]`, default true, preserving today's behaviour. Setting it to false treats blank values as values to search for. `nil` is ignored either way, so params that were never sent still do not become conditions. Three places had to agree: the params filter in Search#initialize, the default predicate validator, and Predicate#validate, which now treats an explicitly empty array for an array-wanting predicate as a meaningful filter. The validator consults the option at search time rather than capturing it when the predicate is defined, so setting it in an initializer applies to predicates registered before it runs. Closes #722 Closes #1664 Co-Authored-By: pekopekopekopayo <pekopekopekopayo@users.noreply.github.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ea39a75 to
7e98e13
Compare
…k-values # Conflicts: # docs/docs/getting-started/configuration.md # lib/ransack/configuration.rb
With ignore_blank_values off, Predicate#validate still cast the value to the column type before running the validator. For an integer or boolean column that turned '' into nil, the validator rejected it, and the condition vanished: Person.ransack(parent_id_eq: '').result.to_sql # => SELECT "people".* FROM "people" (every row) That is the one outcome the option exists to prevent. The validator now sees the value as given when blanks are meaningful, so the condition is built. Arel renders the cast nil as IS NULL for eq on integer, boolean and date columns; inside _in or with a comparison predicate it matches nothing, which is the safe direction. Also resolves the merge with main: fields_sort_option landed in the same region of the configuration file and its docs. The strip_whitespace lines are left to #1688 so the two branches no longer overlap. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…lues # Conflicts: # docs/docs/getting-started/configuration.md # lib/ransack/search.rb

Note
This PR was opened by Claude (Claude Code), acting on behalf of @scarroll32.
It is a reworking of @pekopekopekopayo's #1664 — thank you for raising it.
Closes #722. Closes #1664. Addresses the request behind #1592.
The request, and why it can't just be switched on
#1664 made blank values meaningful unconditionally:
name_eq: ''becomesWHERE name = '',id_in: []matches nothing. The reasoning is sound — as the PR notes, an empty array today causes a full table scan because the condition is dropped entirely, which is a real problem for an API endpoint.But it can't be the default. A blank text input in an HTML form posts
"". Today Ransack ignores it, which is exactly why a search form with empty fields returns everything instead of nothing. Flipped unconditionally, every untouched field becomesWHERE column = ''and the most common Ransack usage pattern silently returns no rows.Both behaviours are correct — for different callers. So this makes it a setting.
config.ignore_blank_valuesDefault
true, which is today's behaviour exactly.nilis ignored under either setting, so params that were never sent still don't become conditions. That distinction is what makes the option safe: absent and blank stop being the same thing.Three places had to agree
This is the part worth reviewing, because getting one wrong makes the option half-work:
Search#initializePredicate::DEFAULT_VALIDATORPredicate#validateThe validator reads
Ransack.options[:ignore_blank_values]at search time rather than capturing it when the predicate is constructed. Predicates are registered at load, before an initializer runs, so a captured value would silently ignore the setting.Tests
Twelve specs across both modes, including that the default still drops blanks (three specs guarding the existing behaviour), that
nilis still dropped when the option is off, and end-to-end assertions thatname_eq: ''produces= ''andid_in: []returns no rows.Full suite: 538 examples, 0 failures, 1 pending (Rails 8.1.3 / Ruby 3.4.9 / SQLite).
Docs
New "Blank values" section on the Configuration page, with a caution against enabling it for form-backed searches. Also documents
strip_whitespacein the initializer example, which was implemented but undocumented.Compatibility
None. The default is unchanged and every existing spec passes untouched.
🤖 Generated with Claude Code