14 June 2013

ActiveRecord newly created association object updates

This is a strange one that took a full day to figure out. I was creating a new item in a has_many association, initially with some default values. Then as processing proceeds, I wanted to conditionally update_attributes to correct some of those values (different changes depending on different conditions). The problem was that the updates were not persisting. I finally figured out a work-around, and so I'll show both here.

The problem

The code below shows the basic setup and processing. Obviously it's been simplified for this blog and the reasons for the various conditional changes to the anchor object have been removed. The problem was that the job_role for anchor failed to change after the update_attributes; in fact, the log shows that no write to the database took place. It was being totally ignored. Status of true was being returned and no errors were logged to anchor.errors. Anchor.new_record? was returning false. Mysterious.

class Events < ActiveRecord::Base
  has_many :duties

     # create a new duty with a given role
  def create_duty_with_role( role )
    return self.duties.create( job_role: role )
  end
end

class Duty <  ActiveRecord::Base
  belongs_to :event
  
  def self.expand_roles( role_list )
        # always create an initial default role
     anchor = Events.create_duty_with_role( default_role )
     
     # after further work, maybe we want to change the default item
     unless role_list.empty?
        anchor.update_attributes( job_role: role_list.first )
     end 
     :
  end
end

The solution

It turns out that adding an object reload after the creation fixes the issue:

        # always create an initial default role
     anchor = Events.create_duty_with_role( default_role )
     anchor.reload

This then makes it possible to perform different operations on the new object.

Conclusion

Hope this helps someone else encountering this strange quirk in ActiveRecord.