ExportXMLWordPrintableJSON

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Minor - P4
    • None
    • Affects Version/s: None
    • Component/s: None
    • None
    • None
    • Ruby Drivers
    • None
    • None
    • None
    • None
    • None
    • None

      When a document's primary key is nil, its has_many criteria is built as foreign_key: nil, which MongoDB matches against every document whose
      foreign key is null or missing. Reads, count, update_all and delete_all
      through that association then hit unrelated records instead of the
      document's own children.

      A nil id is reachable from ordinary code: Model.new(id: "") mongoizes the
      blank string to nil and discards the generated ObjectId, and models that
      redefine _id without a default start out nil. The document cannot be saved
      (the server rejects a nil _id), so this only affects unsaved parents.

      Repro:

        alice = Owner.create!
        Item.create!(label: 'alice-item', owner: alice)
        Item.create!(label: 'loose')            # no owner, legitimate state
      
        Owner.new(id: '').items.delete_all      # => 1, deletes 'loose'
      

      Mongoid already half-holds the opposite position: create/create! on an
      unsaved parent raises UnsavedDocument, and the proxy's to_a returns [].
      Only the query-issuing methods fall through.

      Fix: when the scoping value is nil, make the association criteria match
      nothing, the way has_and_belongs_to_many already does for an empty id list
      (has_and_belongs_to_many.rb:276). The guard belongs at the association
      layer, not at _evolve_object_id_ or in the selector - Model.where(fk: nil)
      is a legitimate query and must keep working.

      Two related gaps to fix at the same time:

      • HasMany::Proxy#remove_all extracts criteria.selector as a plain hash and
        rebuilds a class-level query, so it drops the criteria's "matches nothing"
        marker. Guarding the criteria alone does not cover delete_all/destroy_all.
      • Contextual::None does not implement delete_all, destroy_all or update_all
        and raises NoMethodError, despite documenting interface parity with
        Contextual::Mongo.

      has_one, the *_through associations and the polymorphic paths have the same
      shape and need the same guard.

            Assignee:
            Jamis Buck
            Reporter:
            Dmitry Rybakov
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: