This project is archived and is in readonly mode.

#3096 ✓resolved
Florent2

problem with combined use of touch and autosave options

Reported by Florent2 | August 25th, 2009 @ 10:53 PM | in 2.3.6

In certain circumstances the combined use of :touch and :autosave options provokes updates in the database of objects that have not changed.

Here is an example:

class User < ActiveRecord::Base
  has_many :memberships, :dependent => :destroy, :autosave => true
end
class Group < ActiveRecord::Base
  has_many :memberships, :dependent => :destroy, :autosave => true
end
class Membership < ActiveRecord::Base
  belongs_to :user, :touch => true
  belongs_to :group, :touch => true
end

Having a user Joe, a group Soccerteam and a membership between Joe and Soccerteam, if
1. I call the user 'memberships' method,
2. then update an attribute of the user (for instance if name)
the group Soccerteam will be updated in the database tough none of its own attributes has changed.

Here a console illustrative sequence:
http://pastie.org/594701

This bug does not occur if I do not call the user 'memberships' method before updating one of its attribute. It does not occur either without the :touch option, or without the :autosave option.

Tested with Rails 2.3.3

Comments and changes to this ticket

  • Jamie Rumbelow

    Jamie Rumbelow August 26th, 2009 @ 10:47 AM

    This behavior seems correct - calling the user.memberships touches the group (updating one of it's attributes) and then the autosave falls back down through the associations to find that the group has been changed, thus updating it's attribute.

    Nothing wrong here.

  • Florent2

    Florent2 August 26th, 2009 @ 05:14 PM

    Jamie I am not sure I understand what you wrote.

    From what I see in my console sequence, calling "user.memberships" does not touch the group, it just loads the membership associated to the user. When I save the user, the membership is not updated in the DB as it has not changed itself. As the membership record does not change in the database, I don't understand why the group is updated in the database.

    Sounds like a bug for me.

  • Florent2

    Florent2 August 26th, 2009 @ 06:18 PM

    I've looked in ActiveRecord code and now I think I understand what you mean Jamie.

    :autosave option calls the save method of the loaded association records. In my case the association (membership) has not changed so when its save method is called, the DB record is not changed.

    But calling this save method is enough for the touch mechanism to occur, that's why the group is updated in the database. This is because touch is implemented as a after_save callback.

    I could "fix" my problem by changing the autosave code so that it calls the association save method only if the association itself has changed. In activerecord-2.3.3/lib/active_record, method save_collection_association I changed the last condition

    elsif autosave
      record.save(false)
    end
    
    into
    elsif autosave && record.changed?
      record.save(false)
    end


    I am not familiar with Rails internals and structure, so before going further and submitting a patch with tests, I would like to know if it the right way to fix this issue. Any indication would appreciated :)
  • Kane

    Kane August 28th, 2009 @ 04:38 PM

    only saving the record when it changed seems fine with me and should be done even if it would work with your touch example.
    if somebody needs to save all associated records every time for what ever he might need touch for has_many.

    i thought of a case where people validate the association record with stuff from the parent, say association.name must be present if parent is in state open or something like this. but that wouldnt be affected cause validations would still be done.

    so +1 from me for adding "&& record.changed?"

  • Eloy Duran

    Eloy Duran December 30th, 2009 @ 07:42 PM

    • Assigned user set to “Eloy Duran”
    • Milestone set to 2.3.6
  • Eloy Duran

    Eloy Duran January 8th, 2010 @ 11:21 AM

    • State changed from “new” to “resolved”
  • Florent2

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages