From 70d3625760aac9994790bd023f1b5060fe1d06c5 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 22 Jun 2012 10:29:32 +0100 Subject: disallow mutating a relation once loaded --- activerecord/lib/active_record/errors.rb | 3 ++ .../lib/active_record/relation/query_methods.rb | 38 ++++++++++++---------- activerecord/test/cases/relations_test.rb | 27 +++++++++++++++ 3 files changed, 50 insertions(+), 18 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 9b88bb8178..858b667e22 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -196,4 +196,7 @@ module ActiveRecord "Unknown primary key for table #{model.table_name} in model #{model}." end end + + class ImmutableRelation < ActiveRecordError + end end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 529ddb5e31..e394acfaf2 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -7,34 +7,36 @@ module ActiveRecord Relation::MULTI_VALUE_METHODS.each do |name| class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name}_values # def select_values - @values[:#{name}] || [] # @values[:select] || [] - end # end - # - def #{name}_values=(values) # def select_values=(values) - @values[:#{name}] = values # @values[:select] = values - end # end + def #{name}_values # def select_values + @values[:#{name}] || [] # @values[:select] || [] + end # end + # + def #{name}_values=(values) # def select_values=(values) + raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded + @values[:#{name}] = values # @values[:select] = values + end # end CODE end (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name| class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name}_value # def readonly_value - @values[:#{name}] # @values[:readonly] - end # end - # - def #{name}_value=(value) # def readonly_value=(value) - @values[:#{name}] = value # @values[:readonly] = value - end # end + def #{name}_value # def readonly_value + @values[:#{name}] # @values[:readonly] + end # end CODE end - def create_with_value - @values[:create_with] || {} + Relation::SINGLE_VALUE_METHODS.each do |name| + class_eval <<-CODE, __FILE__, __LINE__ + 1 + def #{name}_value=(value) # def readonly_value=(value) + raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded + @values[:#{name}] = value # @values[:readonly] = value + end # end + CODE end - def create_with_value=(value) - @values[:create_with] = value + def create_with_value + @values[:create_with] || {} end alias extensions extending_values diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 6c5bee7382..8544d36aa8 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1284,4 +1284,31 @@ class RelationTest < ActiveRecord::TestCase Post.scoped.find_by!("1 = 0") end end + + test "loaded relations cannot be mutated by multi value methods" do + relation = Post.scoped + relation.to_a + + assert_raises(ActiveRecord::ImmutableRelation) do + relation.where! 'foo' + end + end + + test "loaded relations cannot be mutated by single value methods" do + relation = Post.scoped + relation.to_a + + assert_raises(ActiveRecord::ImmutableRelation) do + relation.limit! 5 + end + end + + test "loaded relations cannot be mutated by merge!" do + relation = Post.scoped + relation.to_a + + assert_raises(ActiveRecord::ImmutableRelation) do + relation.merge! where: 'foo' + end + end end -- cgit v1.2.3