Skip to content

Add ignore_blank_values config option - #1683

Merged
scarroll32 merged 4 commits into
fix-1653-advanced-blankfrom
feat-1664-ignore-blank-values
Sep 21, 2026
Merged

scarroll32 merged 4 commits into
fix-1653-advanced-blankfrom
feat-1664-ignore-blank-values

Conversation

@scarroll32

Copy link
Copy Markdown
Member

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: '' becomes WHERE 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 becomes WHERE 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_values

Default true, which is today's behaviour exactly.

Ransack.configure { |config| config.ignore_blank_values = false }

Person.ransack(name_eq: "").result.to_sql
# => SELECT "people".* FROM "people" WHERE "people"."name" = ''

Person.ransack(id_in: []).result.to_a
# => []

nil is 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:

Location Role
Search#initialize Drops blank params before the conditions are built at all
Predicate::DEFAULT_VALIDATOR Rejects blank values during condition validation
Predicate#validate An explicitly empty array for an array-wanting predicate is now a filter that matches nothing, not an absent one

The 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 nil is still dropped when the option is off, and end-to-end assertions that name_eq: '' produces = '' and id_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_whitespace in the initializer example, which was implemented but undocumented.

Compatibility

None. The default is unchanged and every existing spec passes untouched.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 High severity

Open (1)
What changed in this PR

Adds configurable handling for blank search values while preserving the existing default behavior.

Changes:

  • Adds ignore_blank_values configuration.
  • 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.

Comment thread lib/ransack/predicate.rb
Comment on lines +12 to +14
else
!v.nil?
end

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@scarroll32
scarroll32 force-pushed the feat-1664-ignore-blank-values branch from ea39a75 to 7e98e13 Compare September 21, 2026 10:21
@scarroll32 scarroll32 mentioned this pull request Sep 21, 2026
scarroll32 and others added 3 commits September 21, 2026 13:07
…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
@scarroll32
scarroll32 changed the base branch from main to fix-1653-advanced-blank September 21, 2026 11:15
@scarroll32
scarroll32 added this pull request to stack #1700 September 21, 2026 11:24
@scarroll32
scarroll32 merged commit 94676fa into main Sep 21, 2026
28 checks passed
@scarroll32
scarroll32 deleted the feat-1664-ignore-blank-values branch September 21, 2026 11:34
@scarroll32 scarroll32 mentioned this pull request Sep 21, 2026
61 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

predicate containing empty string results in ignored query clause

2 participants