Skip to content

Expand a ransack_alias named in advanced-search params - #1731

Merged
scarroll32 merged 2 commits into
mainfrom
fix-1728-alias-advanced-search
Sep 27, 2026
Merged

scarroll32 merged 2 commits into
mainfrom
fix-1728-alias-advanced-search

Conversation

@scarroll32

Copy link
Copy Markdown
Member

Note

This PR was opened by Claude (Claude Code), acting on behalf of @scarroll32.

Closes #1728.

Why

A ransack_alias worked in a simple key (term_cont=a) but not in advanced-search params (a: { '0' => { name: 'term' } }). The simple key goes through Condition.extract, which resolves aliases before the attributes are built. The advanced params name the attribute directly, so the alias reached Attribute.new as-is, passed valid? by being allowlisted under its own name, and bound a column that does not exist. attribute_select lists ransackable_attributes, which includes the alias, so any advanced-search form on a model with an alias offered a choice that 500'd (activerecord-hackery/ransack_demo#113).

What

Condition#attributes= now expands each name through Context#resolve_aliases before building, the same lookup the simple path uses, so the two entry points agree:

  • An alias to one attribute (daddy → parent_name) is built under the target name.
  • An alias to a compound (term → name_or_email) becomes one attribute per segment, joined by the compound's combinator.
  • An alias defined on an associated model and reached through a path (person_term on Article) expands too, since resolve_aliases already handles that.
  • An explicit m in the params wins over the compound's combinator; a blank m, which a form may send after the attributes, does not wipe it.
  • A name that is not an alias is built exactly as before, and a blank name keeps the name.nil? bypass that Grouping#new_condition relies on.

attribute_select is unchanged: it keeps offering the alias, and what it offers now works. The value reads back under the alias from its grouping (grouping.term_cont), as the existing #689 behaviour already did for a single-attribute alias.

Verification

  • 764 examples, 0 failures on SQLite (Active Record 7.2.3.2, Ruby 3.4.9)
  • 8 new examples in ransack_alias_spec.rb under "named in advanced-search params": compound alias, single association alias, alias on an associated model, blank m after the attributes, explicit m winning, alias mixed with a plain attribute, read-back from the grouping, and attribute_select still listing the alias
  • RuboCop clean on the changed files

🤖 Generated with Claude Code

A simple key goes through Condition.extract, which resolves aliases
before the attributes are built. Advanced-search params name the
attribute directly (a: { '0' => { name: 'term' } }), so the alias
reached Attribute.new as-is, passed valid? by being allowlisted under
its own name, and bound a column that does not exist, while
attribute_select offered it as an option.

Condition#attributes= now expands the name through
Context#resolve_aliases first: an alias to one attribute is built
under that name, and an alias to a compound becomes one attribute per
segment, with the compound's combinator as the fallback when the
params carry no explicit one.

Closes #1728

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

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

Combinator fallback currently mishandles invalid and mixed combinators.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Expands ransack_alias values supplied through advanced-search parameters.

Changes:

  • Resolves aliases before building condition attributes.
  • Preserves alias-derived combinators unless explicitly overridden.
  • Adds advanced-search alias coverage.
File Description
lib/​ransack/​nodes/​condition.rb Expands aliased attributes and derives combinators.
spec/​ransack/​active_record/​ransack_alias_spec.rb Tests advanced-search alias behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/ransack/nodes/condition.rb Outdated
# `name_or_email` ORs its two attributes without an `m` in the params.
def combinator
@attributes.size > 1 ? @combinator : nil
@attributes.size > 1 ? (@combinator || @alias_combinator) : nil

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.

Good catch, fixed in 138cd40. Condition#combinator= now records whether a non-blank value was supplied, and the alias combinator is used only when none was. An unknown m still normalises to nil and fails valid_combinator?, so the condition is dropped (or raises Invalid combinator under ransack!) like any other multi-attribute condition. Spec added for both modes.

Node#combinator= normalises an unknown combinator such as `nand` to
nil in a permissive search, so the alias fallback would have run the
expanded condition with the alias's own combinator where any other
multi-attribute condition is dropped by valid_combinator?. Track
whether a non-blank combinator was supplied and use the fallback only
for a missing or blank `m`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@scarroll32
scarroll32 merged commit cf3f171 into main Sep 27, 2026
29 checks passed
@scarroll32
scarroll32 deleted the fix-1728-alias-advanced-search branch September 27, 2026 11:02
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.

ransack_alias is not resolved for advanced-search attributes (a: ... name:), so attribute_select offers an option that raises

2 participants