Skip to content

Conversation

@sncalvo
Copy link
Contributor

@sncalvo sncalvo commented Jan 2, 2026

Description

Added with_scope to Definition and @scope instance variable to allow controlling logic for scopes.

This PR addresses this issue.

Changes

  • ActiveFlag::Definition:
    • Added @scope instance variable (defaults to the model class).
    • Added with_scope(scope) method to create a shallow copy of the definition bound to a specific scope.
    • Updated set_all! and unset_all! to perform update_all on @scope instead of @klass.
  • ActiveFlag module:
    • Updated the flag class method to define the flag accessor (e.g., languages) on generated_relation_methods (if available). This allows the accessor to capture self (the relation) as the scope when called on an ActiveRecord::Relation.
  • Tests:
    • Added test_scoped_set_all_and_unset_all to verify that scoping works as expected for both setting and unsetting flags.

@kenn
Copy link
Owner

kenn commented Jan 3, 2026

@claude @codex review

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@kenn
Copy link
Owner

kenn commented Jan 3, 2026

Thanks!

My intention was to keep the minimal surface area by only supporting top‑level scoping. We should add a minimal guard in case someone tries to call set_all!/unset_all! on a relation with joins/group/distinct/limitupdate_all has AR caveats there — but given the intended usage this seems fine.

What do you think about adding something like this?

# definition.rb
    def set_all!(key)
      ensure_simple_scope!
      @scope.update_all("#{@column} = COALESCE(#{@column}, 0) | #{@maps[key]}")
    end

    def unset_all!(key)
      ensure_simple_scope!
      @scope.update_all("#{@column} = COALESCE(#{@column}, 0) & ~#{@maps[key]}")
    end

  private

    def ensure_simple_scope!
      return unless @scope.is_a?(ActiveRecord::Relation)

      extras = @scope.values.except(:where)
      return if extras.values.all? {|value| value.nil? || (value.respond_to?(:empty?) && value.empty?) }

      raise ArgumentError, "set_all!/unset_all! only support simple where scopes"
    end
# active_flag_test.rb
  def test_scoped_set_all_rejects_complex_relations
    scope = Profile.joins(:users)
    assert_raises(ArgumentError) { scope.languages.set_all!(:chinese) }
    assert_raises(ArgumentError) { scope.languages.unset_all!(:chinese) }
  end

this will avoid generation of invalid SQL or updating wrong tables due to ambigous names
@sncalvo
Copy link
Contributor Author

sncalvo commented Jan 3, 2026

Yes. You are totally right. Just added that. I made the error message more explicit. Let me know if it seems like too much.

@kenn kenn merged commit 683260f into kenn:master Jan 5, 2026
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.

2 participants