Hi, When we update a record via an update form, is there an easy way to find out the fields that have been changed. If the update is successful, i want to display: The following fields have been changed: field-name = new-value ... Thanks, Lantis. -- Posted via http://www.ruby-forum.com/.
There is a recipe for doing this called "Keeping Track of Who Did What" in the book "Rails Recipes" (http://pragmaticprogrammer.com/titles/fr_rr/). -Jeremy -- Posted with http://DevLists.com. Sign up and save your mailbox.
It''s not really what i want. That recipe shows how to keep track of user''s activity. What i want is to find out what was changed in the edit operation (the fields of the record & the new values). Thanks anyway, Lantis. -- Posted via http://www.ruby-forum.com/.
I am also interested in a solution to this problem since I have a form with over 100''s text fields and I dont want to load teh DB with updating all fields every time only one is updated... My current idea would be to associate each text field with a hiden field containing the old_value of the field. And when you do the update, you only update the records for which old_field != new_field. But still, I dont find this solution very elegant. Since rails know the value of all fields (that is how it is able to auto-populate them), it should be aware of changes to any of these fields by comparing the params hash with the hash in memory. Anyone can comment on this? I am just guessing... -- Posted via http://www.ruby-forum.com/.
Hello, Lantis :> It''s not really what i want. That recipe shows how to keep track of > user''s activity. What i want is to find out what was changed in the edit > operation (the fields of the record & the new .Alain :> [...] Since rails know the value of all fields (that is how it > is able to auto-populate them), it should be aware of changes > to any of these fields by comparing the > params hash with the hash in memory.Yes, I think that''s the way we should do it, if Rails doesn''t do it, let''s do it instead ! Assuming a Person model, here a typical scaffolded code... def edit @person = Person.find(params[:id]) end def update @person = Person.find(params[:id]) if @person.update_attributes(params[:person]) flash[:notice] = ''Person was successfully updated.'' redirect_to :action => ''show'', :id => @person else render :action => ''edit'' end end So, the idea is to take the params[:person] hash and remove the not-changing key/value pairs. def update @person = Person.find(params[:id]) attr = @person.attributes new_attr = params[:person] new_attr.delete_if { |k,v| attr.has_key?(k) && attr[k] == v } # => updated fields in new_attr Hash # if we wanna display it, use a @new_attr variable. if @person.update_attributes(new_attr) flash[:notice] = ''Person was successfully updated.'' redirect_to :action => ''show'', :id => @person else render :action => ''edit'' end end No tested though, but it should do the trick. So if it works, you can add a method to AR::B like that : def update_only_changed_attributes(attrs) attrs.delete_if do|key,value| has_attribute?(key) && self[key] == value end update_attributes(attrs) end Not tested... again :) In the debugging process of this method, i''m wondering if we have to check for the primary key, to remove it from the hash or not. And other issues i haven''t suspected... (do i have to stringify the keys ?) -- Jean-Fran?ois. -- ? la renverse.
Alain wrote:> I am also interested in a solution to this problem since I have a form > with over 100''s text fields and I dont want to load teh DB with updating > all fields every time only one is updated... > > My current idea would be to associate each text field with a hiden field > containing the old_value of the field. And when you do the update, you > only update the records for which old_field != new_field. > > But still, I dont find this solution very elegant. Since rails know the > value of all fields (that is how it is able to auto-populate them), it > should be aware of changes to any of these fields by comparing the > params hash with the hash in memory. > > Anyone can comment on this? I am just guessing...Yes, I think it''d be useful for Active Record to track which attributes in a model have changed, both allowing the user to identify changed fields, and restricting DB updates to only those changed fields. I actually wrote a mod to implement this, but I don''t think I''ve fully tested it. It adds a @changed_attributes hash to a model. What held me up was also implementing a @changed_association hash which allowed AR to not only automatically save the new records in an object''s descended associates, but also any changed attribute in those descendants. This would simplify controller code. Here''s the code to get the flavour of what is required. Changed lines marked with ''N''. ----------------------------------------------------------------- module ActiveRecord class Base def initialize(attributes = nil) @attributes = attributes_from_column_definition N @changed_attributes = {} @new_record = true ensure_proper_type self.attributes = attributes unless attributes.nil? yield self if block_given? end def write_attribute(attr_name, value) attr_name = attr_name.to_s if (column = column_for_attribute(attr_name)) && column.number? new_value = convert_number_column_value(value) N if new_value != @attributes[attr_name] N @changed_attributes[attr_name] = true N @attributes[attr_name] = new_value end else @attributes[attr_name] = value end end private N def attributes_with_quotes(include_primary_key = true, only_changed = false) attributes.inject({}) do |quoted, (name, value)| if column = column_for_attribute(name) N unless !include_primary_key && column.primary || only_changed && @changed_attributes[name] quoted[name] = quote(value, column) end end quoted end end def update N quoted_attributes = attributes_with_quotes(false,true) connection.update( "UPDATE #{self.class.table_name} " + N "SET #{quoted_comma_pair_list(connection, quoted_attributes)} " + "WHERE #{self.class.primary_key} = #{quote(id)}", "#{self.class.name} Update" N ) unless quoted_attributes.empty? return true end end end ----------------------------------------------------------------- -- We develop, watch us RoR, in numbers too big to ignore.