Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of duplicates for replace on has_many-through #33954

Commits on Nov 6, 2018

  1. Fix handling of duplicates for replace on has_many-through

    There was a bug in the handling of duplicates when
    assigning (replacing) associated records, which made the result
    dependent on whether a given record was associated already before
    being assigned anew. E.g.
    
        post.people = [person, person]
        post.people.count
        # => 2
    
    while
    
        post.people = [person]
        post.people = [person, person]
        post.people.count
        # => 1
    
    This change adds a test to provoke the former incorrect behavior, and
    fixes it.
    
    Cause of the bug was the handling of record collections as sets, and
    using `-` (difference) and `&` (union) operations on them
    indiscriminately. This temporary conversion to sets would eliminate
    duplicates.
    
    The fix is to decorate record collections for these operations, and
    only for the `has_many :through` case. It is done by counting
    occurrences, and use the record together with the occurrence number as
    element, in order to make them work well in sets. Given
    
        a, b = *Person.all
    
    then the collection used for finding the difference or union of
    records would be internally changed from
    
         [a, b, a]
    
    to
    
         [[a, 1], [b, 1], [a, 2]]
    
    for these operations. So a first occurrence and a second occurrence
    would be distinguishable, which is all that is necessary for this
    task.
    
    Fixes rails#33942.
    febeling committed Nov 6, 2018
    Copy the full SHA
    8104589 View commit details
    Browse the repository at this point in the history
  2. Copy the full SHA
    11bad94 View commit details
    Browse the repository at this point in the history
  3. Copy the full SHA
    f915758 View commit details
    Browse the repository at this point in the history