Skip to content

Make search_form_* helpers honour per-search search_key (#1118) - #1676

Merged
scarroll32 merged 1 commit into
activerecord-hackery:mainfrom
ryoya1122:fix/issue-1118-search-form-search-key
Sep 21, 2026
Merged

scarroll32 merged 1 commit into
activerecord-hackery:mainfrom
ryoya1122:fix/issue-1118-search-form-search-key

Conversation

@ryoya1122

Copy link
Copy Markdown
Contributor

Closes #1118.

Problem

When a search_key: is passed to Model.ransack, the form-building helpers ignore it. The inputs are emitted under the global default key (q[...]) regardless of the override:

q = Person.ransack({}, search_key: :people_search)
search_form_for(q) { |f| f.text_field :name_eq }
# => <input type="text" name="q[name_eq]" id="q_name_eq" />
#                       ^^^ should be people_search[name_eq] / people_search_name_eq

The same applies to search_form_with and turbo_search_form_for. sort_link and sort_url already read the key from the search's context, so the form path is the outlier.

Cause

The two private finalisers used the global default instead of asking the search:

def finalize_form_options(options, html_options)
  options[:as] ||= Ransack.options[:search_key]   # <- global, ignores per-search override
  ...
end

def finalize_form_with_options(options, html_options)
  options[:scope] ||= Ransack.options[:search_key] # <- same
  ...
end

The reporter linked both lines in #1118.

Fix

finalize_form_options / finalize_form_with_options now take the search and read search.context.search_key, the same source sort_link / sort_url already use (see lib/ransack/helpers/form_helper.rb#L200 and #L249).

Context#search_key is initialised as options[:search_key] || Ransack.options[:search_key], so the global default still applies when no per-search override is given.

Compatibility

Model.ransack call Before After
Person.ransack(...) inputs under q[...] (global default) inputs under q[...] (unchanged)
Person.ransack(...) after Ransack.configure { ... :example } inputs under example[...] (global) inputs under example[...] (unchanged)
Person.ransack(..., search_key: :people_search) inputs under q[...] ❌ (#1118) inputs under people_search[...] ✓
options[:as] / options[:scope] explicitly set by caller wins via `

The finalize_form_* methods are private, so the signature change is internal.

Tests

Two new specs in spec/ransack/helpers/form_helper_spec.rb, alongside the existing global-default tests, both red before the fix and green after:

  • #search_form_for with per-search search_key -> expects people_search_name_eq
  • #search_form_with with per-search search_key -> expects people_search[name_eq]

Full suite: 514 examples, 0 failures, 1 pending on v5.0.0 + this branch (SQLite, ActiveRecord 7.2.3.1, Ruby 3.4.9).

Targets v5.0.0 per #1640.

…h search_key (activerecord-hackery#1118)

`sort_link` and `sort_url` already read the search key from the
search's context (`search.context.search_key`). The form-building
helpers were instead falling back to the global `Ransack.options[:search_key]`
in `finalize_form_options` / `finalize_form_with_options`, which meant
that passing `search_key:` to `Model.ransack` was silently ignored:
inputs were emitted under `q[...]` regardless of the override.

The two private finalisers now take the `search` object and use
`search.context.search_key`. `Context#search_key` already falls back
to `Ransack.options[:search_key]` when no per-search override is given,
so the global default continues to apply for the unconfigured case.
@scarroll32
scarroll32 deleted the branch activerecord-hackery:main September 21, 2026 09:40
@scarroll32 scarroll32 closed this Sep 21, 2026
@scarroll32 scarroll32 reopened this Sep 21, 2026
@scarroll32
scarroll32 changed the base branch from v5.0.0 to main September 21, 2026 09:41
@scarroll32

Copy link
Copy Markdown
Member

Note

Comment from Claude (Claude Code), acting on behalf of @scarroll32.

Thanks @ryoya1122. Good catch that sort_link/sort_url already read search.context.search_key while the form helpers went straight to the global — that asymmetry was the whole of #1118. Reading from the context also means the global default still applies when no override is given, so existing apps are unaffected.

Retargeted from v5.0.0 to main — the branches have been consolidated (#1647).

Verified locally merged into current main — Rails 8.1.3 / Ruby 3.4.9 / SQLite: 519 examples, 0 failures, 1 pending.

Merging with an admin override: the branch predates #1667 so the Rails 8.1 / Ruby 3.3–4.0 required contexts can't report on it; every job it does define is green.

@scarroll32
scarroll32 merged commit 39b9951 into activerecord-hackery:main Sep 21, 2026
24 checks passed
scarroll32 added a commit that referenced this pull request Sep 21, 2026
Three changes merged for 4.5.0 had no documentation:

enum (#1665) was entirely undocumented. Adds a section showing that an
Active Record enum can be searched by label, with eq and in examples, so
a select built from Model.enums.keys can be posted back unchanged.

Per-search search_key (#1676): the configuration page still told readers
to repeat the key as `as: :log_search` in the view, which was the
workaround for the bug that PR fixed. The helpers now read it from the
search object.

Symbol allowlists (#1539): records that ransackable_attributes and
ransackable_associations accept symbols or strings interchangeably, and
that a symbol list previously matched nothing.

Each example was run against the spec schema.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

Use search_key from the search context for search_form_for

2 participants