Make tagged_with take keywords and reject unknown options - #80
Merged
Conversation
The scope declared no keyword parameters, so every option arrived in a
catch-all hash and a typo was silently swallowed:
Post.tagged_with(%w[ruby], anyy: true) # ran as if nothing was passed
It now validates against the four options it accepts and raises
ArgumentError naming the unknown key and the expected ones. It also drops
three lines of hand-rolled defaulting and the options.delete(:on) that
made the caller-hash mutation possible in the first place.
Backwards compatible. Ruby 3 will not convert a positional hash into
keywords, so `tagged_with(tags, options)` would have broken; the scope
takes that hash explicitly and merges it. Both call styles are tested,
including that the caller's hash comes back unmutated.
Deliberately not addressed: the `return if base.respond_to?(:tagged_with)`
guard. It silently skips defining the scope when the host model already
has one, while the four generated column scopes call tagged_with
unconditionally — so a host with an incompatible implementation gets four
quietly broken scopes. Raising there would leave a model that defines its
own tagged_with no way to use the gem at all, so the fix is a judgement
call for the maintainers rather than something to slip into this commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
igor-alexandrov
force-pushed
the
indep/tagged-with-options
branch
from
August 18, 2026 13:13
cbfeade to
deb2386
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The scope declared no keyword parameters, so every option arrived in a catch-all hash and a typo was silently swallowed:
It now validates against the four options it accepts:
That also removes three lines of hand-rolled defaulting and the
options.delete(:on)that made caller-hash mutation possible.Backwards compatible
Ruby 3 does not convert a positional hash into keywords, so pure keywords would have broken any caller building an options hash:
The scope takes that hash explicitly and merges it, so both call styles work — and typos raise whichever style they arrive by. Tested, including that the caller's hash comes back unmutated.
What I did not fix, and why
The
return if base.respond_to?(:tagged_with)guard silently skips defining the scope when the host model already has one, while the four generated column scopes calltagged_withunconditionally — so a host with an incompatible implementation gets four quietly broken scopes.Both obvious fixes are worse than the problem: raising leaves a model that defines its own
tagged_withunable to use the gem at all; dropping the guard silently overwrites the host's method. That is a judgement call about the gem's contract, so it belongs to the maintainers rather than being slipped in here.🤖 Generated with Claude Code