Changeset 7693
- Timestamp:
- 09/30/07 07:09:44 (9 months ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record/associations.rb (modified) (1 diff)
- trunk/activerecord/lib/active_record/base.rb (modified) (5 diffs)
- trunk/activerecord/test/associations_test.rb (modified) (1 diff)
- trunk/activerecord/test/base_test.rb (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r7692 r7693 1 1 *2.0.0 [Preview Release]* (September 29th, 2007) [Includes duplicates of changes from 1.14.2 - 1.15.3] 2 3 * Add attr_readonly to specify columns that are skipped during a normal ActiveRecord #save operation. Closes #6896 [dcmanges] 4 5 class Comment < ActiveRecord::Base 6 # Automatically sets Article#comments_count as readonly. 7 belongs_to :article, :counter_cache => :comments_count 8 end 9 10 class Article < ActiveRecord::Base 11 attr_readonly :approved_comments_count 12 end 2 13 3 14 * Make size for has_many :through use counter cache if it exists. Closes #9734 [xaviershay] trunk/activerecord/lib/active_record/associations.rb
r7666 r7693 842 842 "before_destroy '#{reflection.name}.class.decrement_counter(\"#{cache_column}\", #{reflection.primary_key_name})" + 843 843 " unless #{reflection.name}.nil?'" 844 ) 844 ) 845 846 module_eval( 847 "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name})" 848 ) 845 849 end 846 850 end trunk/activerecord/lib/active_record/base.rb
r7666 r7693 637 637 end 638 638 639 # Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards. 640 def attr_readonly(*attributes) 641 write_inheritable_array("attr_readonly", attributes - (readonly_attributes || [])) 642 end 643 644 # Returns an array of all the attributes that have been specified as readonly. 645 def readonly_attributes 646 read_inheritable_attribute("attr_readonly") 647 end 639 648 640 649 # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, … … 1954 1963 connection.update( 1955 1964 "UPDATE #{self.class.table_name} " + 1956 "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false ))} " +1965 "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false))} " + 1957 1966 "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}", 1958 1967 "#{self.class.name} Update" … … 2009 2018 end 2010 2019 end 2020 2021 # Removes attributes which have been marked as readonly. 2022 def remove_readonly_attributes(attributes) 2023 unless self.class.readonly_attributes.nil? 2024 attributes.delete_if { |key, value| self.class.readonly_attributes.include?(key.gsub(/\(.+/,"").intern) } 2025 else 2026 attributes 2027 end 2028 end 2011 2029 2012 2030 # The primary key and inheritance column can never be set by mass-assignment for security reasons. … … 2019 2037 # Returns copy of the attributes hash where all the values have been safely quoted for use in 2020 2038 # an SQL statement. 2021 def attributes_with_quotes(include_primary_key = true )2022 attributes.inject({}) do |quoted, (name, value)|2039 def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true) 2040 quoted = attributes.inject({}) do |quoted, (name, value)| 2023 2041 if column = column_for_attribute(name) 2024 2042 quoted[name] = quote_value(value, column) unless !include_primary_key && column.primary … … 2026 2044 quoted 2027 2045 end 2046 include_readonly_attributes ? quoted : remove_readonly_attributes(quoted) 2028 2047 end 2029 2048 trunk/activerecord/test/associations_test.rb
r7675 r7693 1176 1176 assert_equal 1, Topic.find(topic.id)[:replies_count] 1177 1177 end 1178 1179 def test_belongs_to_counter_after_save 1180 topic = Topic.create("title" => "monday night") 1181 topic.replies.create("title" => "re: monday night", "content" => "football") 1182 assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 1183 1184 topic.save 1185 assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 1186 end 1187 1188 def test_belongs_to_counter_after_update_attributes 1189 topic = Topic.create("title" => "37s") 1190 topic.replies.create("title" => "re: 37s", "content" => "rails") 1191 assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 1192 1193 topic.update_attributes("title" => "37signals") 1194 assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 1195 end 1178 1196 1179 1197 def test_assignment_before_parent_saved trunk/activerecord/test/base_test.rb
r7666 r7693 46 46 class TightDescendant < TightPerson 47 47 attr_accessible :phone_number 48 end 49 50 class ReadonlyTitlePost < Post 51 attr_readonly :title 48 52 end 49 53 … … 841 845 assert_equal [ :name, :address, :phone_number ], TightDescendant.accessible_attributes 842 846 end 847 848 def test_readonly_attributes 849 assert_equal [ :title ], ReadonlyTitlePost.readonly_attributes 850 851 post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable") 852 post.reload 853 assert_equal "cannot change this", post.title 854 855 post.update_attributes(:title => "try to change", :body => "changed") 856 post.reload 857 assert_equal "cannot change this", post.title 858 assert_equal "changed", post.body 859 end 843 860 844 861 def test_multiparameter_attributes_on_date … … 1223 1240 1224 1241 def test_increment_attribute 1225 assert_equal 1, topics(:first).replies_count1226 topics(:first).increment! :replies_count1227 assert_equal 2, topics(:first, :reload).replies_count1228 1229 topics(:first).increment(:replies_count).increment!(:replies_count)1230 assert_equal 4, topics(:first, :reload).replies_count1242 assert_equal 50, accounts(:signals37).credit_limit 1243 accounts(:signals37).increment! :credit_limit 1244 assert_equal 51, accounts(:signals37, :reload).credit_limit 1245 1246 accounts(:signals37).increment(:credit_limit).increment!(:credit_limit) 1247 assert_equal 53, accounts(:signals37, :reload).credit_limit 1231 1248 end 1232 1249 … … 1238 1255 1239 1256 def test_decrement_attribute 1240 topics(:first).increment(:replies_count).increment!(:replies_count) 1241 assert_equal 3, topics(:first).replies_count 1242 1243 topics(:first).decrement!(:replies_count) 1244 assert_equal 2, topics(:first, :reload).replies_count 1245 1246 topics(:first).decrement(:replies_count).decrement!(:replies_count) 1247 assert_equal 0, topics(:first, :reload).replies_count 1257 assert_equal 50, accounts(:signals37).credit_limit 1258 1259 accounts(:signals37).decrement!(:credit_limit) 1260 assert_equal 49, accounts(:signals37, :reload).credit_limit 1261 1262 accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit) 1263 assert_equal 47, accounts(:signals37, :reload).credit_limit 1248 1264 end 1249 1265