active record associations

I want to accomplish the following. I have an object that can be edited. However, it can occur that two people might edit the object at the same time. Instead of locking the object down, I prefer to tell the user how their version differs from the last version that was committed.

Kinda like:

respond_to do |format|   @document = Document.find_by_id(1)   @document.attributes = params[:document]   @changes = @document.diff(Document.find_by_id(1))    format.html { render :action => "edit" } end

The edit screen then renders the changes for the user to compare. The user can then apply some changes or ignore the changes and save.

This works fine for regular fields, but when the object has has_many assoctiations, then the following would occur.

respond_to do |format|   @document = Document.find_by_id(1)   @document.attributes = params[:document] # => this call would update the database for all has_many associations   @changes = @document.diff(Document.find_by_id(1)) #=> retrieving the previous object state from the database is not possible since the associations have changed    format.html { render :action => "edit" } end

I also tried to compare the object to the attributes kinda like this;

respond_to do |format|   @document = Document.find_by_id(1)   @changes = @document.diff(params[:document])    format.html { render :action => "edit" } end

But then the user's changes aren't stored on the object and all updates are lost.

Any help is appreciated.

This sounds like the dirty object feature of Rails 2.1 would work great: http://ryandaigle.com/articles/2008/3/31/what-s-new-in-edge-rails-dirty-objects

Maybe even try to utilize some callback methods so you can capture and display the changes to the user: http://railsforum.com/viewtopic.php?id=23001

The dirty object feature doesn't work for has_many associations. I solved the problem by wrapping a transaction around the code to revert the changes in the database. I kinda wish, ror could keep the functionality between regular fields and association fields consistent to avoid confusion.

kinda like:

class Person   has_many :cars end

person = Person.find_by_name("Jack") person.cars

=> [#<Car id: 2, name: "BMW", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">]

person.cars=[Car.find_by_name("Porsche"), Car.find_by_name("VW")] person.cars

=> [#<Car id: 1, name: "Porsche", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">, #<Car id: 3, name: "VW", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">]

person.changed?

=> true

person.changes

=> {"cars"=>[[#<Car id: 2, name: "BMW", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">], [#<Car id: 1, name: "Porsche", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">, #<Car id: 3, name: "VW", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">]]}

person.save #associations are saved in the database

However ror returns the following

person = Person.find_by_name("Jack") person.cars

=> [#<Car id: 2, name: "BMW", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">]

person.cars=[Car.find_by_name("Porsche"), Car.find_by_name("VW")] #associations are saved in the database person.cars

=> [#<Car id: 1, name: "Porsche", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">, #<Car id: 3, name: "VW", created_at: "2008-11-04 03:04:46", updated_at: "2008-11-04 03:04:46">]

person.changed?

=> false

person.changes

=> {}