From 66d05f5e2c7ac6b18220956fbcf34efcd32638fc Mon Sep 17 00:00:00 2001 From: Rick Olson Date: Sun, 30 Sep 2007 07:09:44 +0000 Subject: Add attr_readonly to specify columns that are skipped during a normal ActiveRecord #save operation. Closes #6896 [dcmanges] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7693 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/lib/active_record/associations.rb | 6 +++++- activerecord/lib/active_record/base.rb | 25 ++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index e269775fd5..1ec7d6021f 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -841,7 +841,11 @@ module ActiveRecord module_eval( "before_destroy '#{reflection.name}.class.decrement_counter(\"#{cache_column}\", #{reflection.primary_key_name})" + " unless #{reflection.name}.nil?'" - ) + ) + + module_eval( + "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name})" + ) end end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index a4ebaf4e93..34685a78e1 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -636,6 +636,15 @@ module ActiveRecord #:nodoc: read_inheritable_attribute("attr_accessible") end + # Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards. + def attr_readonly(*attributes) + write_inheritable_array("attr_readonly", attributes - (readonly_attributes || [])) + end + + # Returns an array of all the attributes that have been specified as readonly. + def readonly_attributes + read_inheritable_attribute("attr_readonly") + end # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. @@ -1953,7 +1962,7 @@ module ActiveRecord #:nodoc: def update connection.update( "UPDATE #{self.class.table_name} " + - "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " + + "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false))} " + "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}", "#{self.class.name} Update" ) @@ -2008,6 +2017,15 @@ module ActiveRecord #:nodoc: raise "Declare either attr_protected or attr_accessible for #{self.class}, but not both." end end + + # Removes attributes which have been marked as readonly. + def remove_readonly_attributes(attributes) + unless self.class.readonly_attributes.nil? + attributes.delete_if { |key, value| self.class.readonly_attributes.include?(key.gsub(/\(.+/,"").intern) } + else + attributes + end + end # The primary key and inheritance column can never be set by mass-assignment for security reasons. def attributes_protected_by_default @@ -2018,13 +2036,14 @@ module ActiveRecord #:nodoc: # Returns copy of the attributes hash where all the values have been safely quoted for use in # an SQL statement. - def attributes_with_quotes(include_primary_key = true) - attributes.inject({}) do |quoted, (name, value)| + def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true) + quoted = attributes.inject({}) do |quoted, (name, value)| if column = column_for_attribute(name) quoted[name] = quote_value(value, column) unless !include_primary_key && column.primary end quoted end + include_readonly_attributes ? quoted : remove_readonly_attributes(quoted) end # Quote strings appropriately for SQL statements. -- cgit v1.2.3