aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases')
-rw-r--r--activerecord/test/cases/associations/eager_test.rb17
-rw-r--r--activerecord/test/cases/associations/inner_join_association_test.rb30
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb292
-rw-r--r--activerecord/test/cases/autosave_association_test.rb29
-rwxr-xr-xactiverecord/test/cases/base_test.rb18
-rw-r--r--activerecord/test/cases/calculations_test.rb20
-rw-r--r--activerecord/test/cases/finder_test.rb6
-rw-r--r--activerecord/test/cases/helper.rb8
-rw-r--r--activerecord/test/cases/locking_test.rb2
-rw-r--r--activerecord/test/cases/method_scoping_test.rb174
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb51
-rw-r--r--activerecord/test/cases/readonly_test.rb41
-rw-r--r--activerecord/test/cases/relations_test.rb167
-rw-r--r--activerecord/test/cases/validations/uniqueness_validation_test.rb2
-rw-r--r--activerecord/test/cases/validations_repair_helper.rb35
-rw-r--r--activerecord/test/cases/validations_test.rb6
16 files changed, 701 insertions, 197 deletions
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index d5a4d9007b..ffa6d45948 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -61,14 +61,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_with_two_tables_in_from_without_getting_double_quoted
- posts = Post.find(:all,
- :select => "posts.*",
- :from => "authors, posts",
- :include => :comments,
- :conditions => "posts.author_id = authors.id",
- :order => "posts.id"
- )
-
+ posts = Post.select("posts.*").from("authors, posts").eager_load(:comments).where("posts.author_id = authors.id").order("posts.id").to_a
assert_equal 2, posts.first.comments.size
end
@@ -469,7 +462,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
posts = nil
- Post.with_scope(:find => {
+ Post.send(:with_scope, :find => {
:include => :comments,
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'"
}) do
@@ -477,7 +470,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal 2, posts.size
end
- Post.with_scope(:find => {
+ Post.send(:with_scope, :find => {
:include => [ :comments, :author ],
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')"
}) do
@@ -487,7 +480,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the_eagers
- Post.with_scope(:find => { :conditions => "1=1" }) do
+ Post.send(:with_scope, :find => { :conditions => "1=1" }) do
posts = authors(:david).posts.find(:all,
:include => :comments,
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
@@ -506,7 +499,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_with_scoped_order_using_association_limiting_without_explicit_scope
posts_with_explicit_order = Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :order => 'posts.id DESC', :limit => 2)
- posts_with_scoped_order = Post.with_scope(:find => {:order => 'posts.id DESC'}) do
+ posts_with_scoped_order = Post.send(:with_scope, :find => {:order => 'posts.id DESC'}) do
Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :limit => 2)
end
assert_equal posts_with_explicit_order, posts_with_scoped_order
diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb
index 5f08c40005..18a1cd3cd0 100644
--- a/activerecord/test/cases/associations/inner_join_association_test.rb
+++ b/activerecord/test/cases/associations/inner_join_association_test.rb
@@ -9,84 +9,84 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations
def test_construct_finder_sql_creates_inner_joins
- sql = Author.send(:construct_finder_sql, :joins => :posts)
+ sql = Author.joins(:posts).to_sql
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
end
def test_construct_finder_sql_cascades_inner_joins
- sql = Author.send(:construct_finder_sql, :joins => {:posts => :comments})
+ sql = Author.joins(:posts => :comments).to_sql
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
assert_match /INNER JOIN .?comments.? ON .?comments.?.post_id = posts.id/, sql
end
def test_construct_finder_sql_inner_joins_through_associations
- sql = Author.send(:construct_finder_sql, :joins => :categorized_posts)
+ sql = Author.joins(:categorized_posts).to_sql
assert_match /INNER JOIN .?categorizations.?.*INNER JOIN .?posts.?/, sql
end
def test_construct_finder_sql_applies_association_conditions
- sql = Author.send(:construct_finder_sql, :joins => :categories_like_general, :conditions => "TERMINATING_MARKER")
+ sql = Author.joins(:categories_like_general).where("TERMINATING_MARKER").to_sql
assert_match /INNER JOIN .?categories.? ON.*AND.*.?General.?(.|\n)*TERMINATING_MARKER/, sql
end
def test_construct_finder_sql_applies_aliases_tables_on_association_conditions
- result = Author.find(:all, :joins => [:thinking_posts, :welcome_posts])
+ result = Author.joins(:thinking_posts, :welcome_posts).to_a
assert_equal authors(:david), result.first
end
def test_construct_finder_sql_unpacks_nested_joins
- sql = Author.send(:construct_finder_sql, :joins => {:posts => [[:comments]]})
+ sql = Author.joins(:posts => [[:comments]]).to_sql
assert_no_match /inner join.*inner join.*inner join/i, sql, "only two join clauses should be present"
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
assert_match /INNER JOIN .?comments.? ON .?comments.?.post_id = .?posts.?.id/, sql
end
def test_construct_finder_sql_ignores_empty_joins_hash
- sql = Author.send(:construct_finder_sql, :joins => {})
+ sql = Author.joins({}).to_sql
assert_no_match /JOIN/i, sql
end
def test_construct_finder_sql_ignores_empty_joins_array
- sql = Author.send(:construct_finder_sql, :joins => [])
+ sql = Author.joins([]).to_sql
assert_no_match /JOIN/i, sql
end
def test_find_with_implicit_inner_joins_honors_readonly_without_select
- authors = Author.find(:all, :joins => :posts)
+ authors = Author.joins(:posts).to_a
assert !authors.empty?, "expected authors to be non-empty"
assert authors.all? {|a| a.readonly? }, "expected all authors to be readonly"
end
def test_find_with_implicit_inner_joins_honors_readonly_with_select
- authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
+ authors = Author.joins(:posts).select('authors.*').to_a
assert !authors.empty?, "expected authors to be non-empty"
assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
end
def test_find_with_implicit_inner_joins_honors_readonly_false
- authors = Author.find(:all, :joins => :posts, :readonly => false)
+ authors = Author.joins(:posts).readonly(false).to_a
assert !authors.empty?, "expected authors to be non-empty"
assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
end
def test_find_with_implicit_inner_joins_does_not_set_associations
- authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
+ authors = Author.joins(:posts).select('authors.*')
assert !authors.empty?, "expected authors to be non-empty"
assert authors.all? {|a| !a.send(:instance_variable_names).include?("@posts")}, "expected no authors to have the @posts association loaded"
end
def test_count_honors_implicit_inner_joins
- real_count = Author.find(:all).sum{|a| a.posts.count }
+ real_count = Author.scoped.to_a.sum{|a| a.posts.count }
assert_equal real_count, Author.count(:joins => :posts), "plain inner join count should match the number of referenced posts records"
end
def test_calculate_honors_implicit_inner_joins
- real_count = Author.find(:all).sum{|a| a.posts.count }
+ real_count = Author.scoped.to_a.sum{|a| a.posts.count }
assert_equal real_count, Author.calculate(:count, 'authors.id', :joins => :posts), "plain inner join count should match the number of referenced posts records"
end
def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions
- real_count = Author.find(:all).select {|a| a.posts.any? {|p| p.title =~ /^Welcome/} }.length
+ real_count = Author.scoped.to_a.select {|a| a.posts.any? {|p| p.title =~ /^Welcome/} }.length
authors_with_welcoming_post_titles = Author.calculate(:count, 'authors.id', :joins => :posts, :distinct => true, :conditions => "posts.title like 'Welcome%'")
assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'"
end
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 47f83db112..1d7604f52b 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -85,7 +85,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
fixtures :men, :faces
def test_parent_instance_should_be_shared_with_child_on_find
- m = Man.find(:first)
+ m = men(:gordon)
f = m.face
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
m.name = 'Bongo'
@@ -96,7 +96,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
def test_parent_instance_should_be_shared_with_eager_loaded_child_on_find
- m = Man.find(:first, :include => :face)
+ m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :face)
f = m.face
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
m.name = 'Bongo'
@@ -104,7 +104,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
f.man.name = 'Mungo'
assert_equal m.name, f.man.name, "Name of man should be the same after changes to child-owned instance"
- m = Man.find(:first, :include => :face, :order => 'faces.id')
+ m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :face, :order => 'faces.id')
f = m.face
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
m.name = 'Bongo'
@@ -114,7 +114,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_built_child
- m = Man.find(:first)
+ m = men(:gordon)
f = m.build_face(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
@@ -125,7 +125,7 @@ class InverseHasOneTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_newly_created_child
- m = Man.find(:first)
+ m = men(:gordon)
f = m.create_face(:description => 'haunted')
assert_not_nil f.man
assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
@@ -135,6 +135,86 @@ class InverseHasOneTests < ActiveRecord::TestCase
assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
end
+ def test_parent_instance_should_be_shared_with_newly_created_child_via_bang_method
+ m = Man.find(:first)
+ f = m.face.create!(:description => 'haunted')
+ assert_not_nil f.man
+ assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
+ f.man.name = 'Mungo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_built_child_when_we_dont_replace_existing
+ m = Man.find(:first)
+ f = m.build_face({:description => 'haunted'}, false)
+ assert_not_nil f.man
+ assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
+ f.man.name = 'Mungo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to just-built-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_created_child_when_we_dont_replace_existing
+ m = Man.find(:first)
+ f = m.create_face({:description => 'haunted'}, false)
+ assert_not_nil f.man
+ assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
+ f.man.name = 'Mungo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_created_child_via_bang_method_when_we_dont_replace_existing
+ m = Man.find(:first)
+ f = m.face.create!({:description => 'haunted'}, false)
+ assert_not_nil f.man
+ assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
+ f.man.name = 'Mungo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_replaced_via_accessor_child
+ m = Man.find(:first)
+ f = Face.new(:description => 'haunted')
+ m.face = f
+ assert_not_nil f.man
+ assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
+ f.man.name = 'Mungo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_replaced_via_method_child
+ m = Man.find(:first)
+ f = Face.new(:description => 'haunted')
+ m.face.replace(f)
+ assert_not_nil f.man
+ assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
+ f.man.name = 'Mungo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_replaced_via_method_child_when_we_dont_replace_existing
+ m = Man.find(:first)
+ f = Face.new(:description => 'haunted')
+ m.face.replace(f, false)
+ assert_not_nil f.man
+ assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance"
+ f.man.name = 'Mungo'
+ assert_equal m.name, f.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
+ end
+
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.find(:first).dirty_face }
end
@@ -144,7 +224,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
fixtures :men, :interests
def test_parent_instance_should_be_shared_with_every_child_on_find
- m = Man.find(:first)
+ m = men(:gordon)
is = m.interests
is.each do |i|
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -156,7 +236,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
end
def test_parent_instance_should_be_shared_with_eager_loaded_children
- m = Man.find(:first, :include => :interests)
+ m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :interests)
is = m.interests
is.each do |i|
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -166,7 +246,7 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal m.name, i.man.name, "Name of man should be the same after changes to child-owned instance"
end
- m = Man.find(:first, :include => :interests, :order => 'interests.id')
+ m = Man.find(:first, :conditions => {:name => 'Gordon'}, :include => :interests, :order => 'interests.id')
is = m.interests
is.each do |i|
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -175,11 +255,10 @@ class InverseHasManyTests < ActiveRecord::TestCase
i.man.name = 'Mungo'
assert_equal m.name, i.man.name, "Name of man should be the same after changes to child-owned instance"
end
-
end
def test_parent_instance_should_be_shared_with_newly_built_child
- m = Man.find(:first)
+ m = men(:gordon)
i = m.interests.build(:topic => 'Industrial Revolution Re-enactment')
assert_not_nil i.man
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -189,8 +268,20 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal m.name, i.man.name, "Name of man should be the same after changes to just-built-child-owned instance"
end
- def test_parent_instance_should_be_shared_with_newly_created_child
+ def test_parent_instance_should_be_shared_with_newly_block_style_built_child
m = Man.find(:first)
+ i = m.interests.build {|ii| ii.topic = 'Industrial Revolution Re-enactment'}
+ assert_not_nil i.topic, "Child attributes supplied to build via blocks should be populated"
+ assert_not_nil i.man
+ assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
+ i.man.name = 'Mungo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to just-built-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_created_child
+ m = men(:gordon)
i = m.interests.create(:topic => 'Industrial Revolution Re-enactment')
assert_not_nil i.man
assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
@@ -200,8 +291,31 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
end
- def test_parent_instance_should_be_shared_with_poked_in_child
+ def test_parent_instance_should_be_shared_with_newly_created_via_bang_method_child
m = Man.find(:first)
+ i = m.interests.create!(:topic => 'Industrial Revolution Re-enactment')
+ assert_not_nil i.man
+ assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
+ i.man.name = 'Mungo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_newly_block_style_created_child
+ m = Man.find(:first)
+ i = m.interests.create {|ii| ii.topic = 'Industrial Revolution Re-enactment'}
+ assert_not_nil i.topic, "Child attributes supplied to create via blocks should be populated"
+ assert_not_nil i.man
+ assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
+ i.man.name = 'Mungo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_poked_in_child
+ m = men(:gordon)
i = Interest.create(:topic => 'Industrial Revolution Re-enactment')
m.interests << i
assert_not_nil i.man
@@ -212,6 +326,30 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance"
end
+ def test_parent_instance_should_be_shared_with_replaced_via_accessor_children
+ m = Man.find(:first)
+ i = Interest.new(:topic => 'Industrial Revolution Re-enactment')
+ m.interests = [i]
+ assert_not_nil i.man
+ assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
+ i.man.name = 'Mungo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
+ end
+
+ def test_parent_instance_should_be_shared_with_replaced_via_method_children
+ m = Man.find(:first)
+ i = Interest.new(:topic => 'Industrial Revolution Re-enactment')
+ m.interests.replace([i])
+ assert_not_nil i.man
+ assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance"
+ m.name = 'Bongo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance"
+ i.man.name = 'Mungo'
+ assert_equal m.name, i.man.name, "Name of man should be the same after changes to replaced-child-owned instance"
+ end
+
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.find(:first).secret_interests }
end
@@ -221,7 +359,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
fixtures :men, :faces, :interests
def test_child_instance_should_be_shared_with_parent_on_find
- f = Face.find(:first)
+ f = faces(:trusting)
m = f.man
assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -231,7 +369,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
end
def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find
- f = Face.find(:first, :include => :man)
+ f = Face.find(:first, :include => :man, :conditions => {:description => 'trusting'})
m = f.man
assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -239,8 +377,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
m.face.description = 'pleasing'
assert_equal f.description, m.face.description, "Description of face should be the same after changes to parent-owned instance"
-
- f = Face.find(:first, :include => :man, :order => 'men.id')
+ f = Face.find(:first, :include => :man, :order => 'men.id', :conditions => {:description => 'trusting'})
m = f.man
assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
f.description = 'gormless'
@@ -250,7 +387,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
end
def test_child_instance_should_be_shared_with_newly_built_parent
- f = Face.find(:first)
+ f = faces(:trusting)
m = f.build_man(:name => 'Charles')
assert_not_nil m.face
assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
@@ -261,7 +398,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
end
def test_child_instance_should_be_shared_with_newly_created_parent
- f = Face.find(:first)
+ f = faces(:trusting)
m = f.create_man(:name => 'Charles')
assert_not_nil m.face
assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
@@ -272,7 +409,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
end
def test_should_not_try_to_set_inverse_instances_when_the_inverse_is_a_has_many
- i = Interest.find(:first)
+ i = interests(:trainspotting)
m = i.man
assert_not_nil m.interests
iz = m.interests.detect {|iz| iz.id == i.id}
@@ -284,11 +421,128 @@ class InverseBelongsToTests < ActiveRecord::TestCase
assert_not_equal i.topic, iz.topic, "Interest topics should not be the same after changes to parent-owned instance"
end
+ def test_child_instance_should_be_shared_with_replaced_via_accessor_parent
+ f = Face.find(:first)
+ m = Man.new(:name => 'Charles')
+ f.man = m
+ assert_not_nil m.face
+ assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
+ f.description = 'gormless'
+ assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance"
+ m.face.description = 'pleasing'
+ assert_equal f.description, m.face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
+ end
+
+ def test_child_instance_should_be_shared_with_replaced_via_method_parent
+ f = faces(:trusting)
+ assert_not_nil f.man
+ m = Man.new(:name => 'Charles')
+ f.man.replace(m)
+ assert_not_nil m.face
+ assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance"
+ f.description = 'gormless'
+ assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance"
+ m.face.description = 'pleasing'
+ assert_equal f.description, m.face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
+ end
+
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).horrible_man }
end
end
+class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
+ fixtures :men, :faces, :interests
+
+ def test_child_instance_should_be_shared_with_parent_on_find
+ f = Face.find(:first, :conditions => {:description => 'confused'})
+ m = f.polymorphic_man
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance"
+ f.description = 'gormless'
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to child instance"
+ m.polymorphic_face.description = 'pleasing'
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance"
+ end
+
+ def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find
+ f = Face.find(:first, :conditions => {:description => 'confused'}, :include => :man)
+ m = f.polymorphic_man
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance"
+ f.description = 'gormless'
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to child instance"
+ m.polymorphic_face.description = 'pleasing'
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance"
+
+ f = Face.find(:first, :conditions => {:description => 'confused'}, :include => :man, :order => 'men.id')
+ m = f.polymorphic_man
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance"
+ f.description = 'gormless'
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to child instance"
+ m.polymorphic_face.description = 'pleasing'
+ assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance"
+ end
+
+ def test_child_instance_should_be_shared_with_replaced_via_accessor_parent
+ face = faces(:confused)
+ old_man = face.polymorphic_man
+ new_man = Man.new
+
+ assert_not_nil face.polymorphic_man
+ face.polymorphic_man = new_man
+
+ assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same before changes to parent instance"
+ face.description = 'Bongo'
+ assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to parent instance"
+ new_man.polymorphic_face.description = 'Mungo'
+ assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
+ end
+
+ def test_child_instance_should_be_shared_with_replaced_via_method_parent
+ face = faces(:confused)
+ old_man = face.polymorphic_man
+ new_man = Man.new
+
+ assert_not_nil face.polymorphic_man
+ face.polymorphic_man.replace(new_man)
+
+ assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same before changes to parent instance"
+ face.description = 'Bongo'
+ assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to parent instance"
+ new_man.polymorphic_face.description = 'Mungo'
+ assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
+ end
+
+ def test_should_not_try_to_set_inverse_instances_when_the_inverse_is_a_has_many
+ i = interests(:llama_wrangling)
+ m = i.polymorphic_man
+ assert_not_nil m.polymorphic_interests
+ iz = m.polymorphic_interests.detect {|iz| iz.id == i.id}
+ assert_not_nil iz
+ assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child"
+ i.topic = 'Eating cheese with a spoon'
+ assert_not_equal i.topic, iz.topic, "Interest topics should not be the same after changes to child"
+ iz.topic = 'Cow tipping'
+ assert_not_equal i.topic, iz.topic, "Interest topics should not be the same after changes to parent-owned instance"
+ end
+
+ def test_trying_to_access_inverses_that_dont_exist_shouldnt_raise_an_error
+ # Ideally this would, if only for symmetry's sake with other association types
+ assert_nothing_raised(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).horrible_polymorphic_man }
+ end
+
+ def test_trying_to_set_polymorphic_inverses_that_dont_exist_at_all_should_raise_an_error
+ # fails because no class has the correct inverse_of for horrible_polymorphic_man
+ assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).horrible_polymorphic_man = Man.first }
+ end
+
+ def test_trying_to_set_polymorphic_inverses_that_dont_exist_on_the_instance_being_set_should_raise_an_error
+ # passes because Man does have the correct inverse_of
+ assert_nothing_raised(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).polymorphic_man = Man.first }
+ # fails because Interest does have the correct inverse_of
+ assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.find(:first).polymorphic_man = Interest.first }
+ end
+end
+
# NOTE - these tests might not be meaningful, ripped as they were from the parental_control plugin
# which would guess the inverse rather than look for an explicit configuration option.
class InverseMultipleHasManyInversesForSameModel < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 9164701601..803e5b25b1 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -31,11 +31,40 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase
assert base.valid_keys_for_has_and_belongs_to_many_association.include?(:autosave)
end
+ def test_should_not_add_the_same_callbacks_multiple_times_for_has_one
+ assert_no_difference_when_adding_callbacks_twice_for Pirate, :ship
+ end
+
+ def test_should_not_add_the_same_callbacks_multiple_times_for_belongs_to
+ assert_no_difference_when_adding_callbacks_twice_for Ship, :pirate
+ end
+
+ def test_should_not_add_the_same_callbacks_multiple_times_for_has_many
+ assert_no_difference_when_adding_callbacks_twice_for Pirate, :birds
+ end
+
+ def test_should_not_add_the_same_callbacks_multiple_times_for_has_and_belongs_to_many
+ assert_no_difference_when_adding_callbacks_twice_for Pirate, :parrots
+ end
+
private
def base
ActiveRecord::Base
end
+
+ def assert_no_difference_when_adding_callbacks_twice_for(model, association_name)
+ reflection = model.reflect_on_association(association_name)
+ assert_no_difference "callbacks_for_model(#{model.name}).length" do
+ model.send(:add_autosave_association_callbacks, reflection)
+ end
+ end
+
+ def callbacks_for_model(model)
+ model.instance_variables.grep(/_callbacks$/).map do |ivar|
+ model.instance_variable_get(ivar)
+ end.flatten
+ end
end
class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index b51c9f0cb3..ebb717812d 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1825,7 +1825,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_scoped_find_conditions
- scoped_developers = Developer.with_scope(:find => { :conditions => 'salary > 90000' }) do
+ scoped_developers = Developer.send(:with_scope, :find => { :conditions => 'salary > 90000' }) do
Developer.find(:all, :conditions => 'id < 5')
end
assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
@@ -1833,7 +1833,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_scoped_find_limit_offset
- scoped_developers = Developer.with_scope(:find => { :limit => 3, :offset => 2 }) do
+ scoped_developers = Developer.send(:with_scope, :find => { :limit => 3, :offset => 2 }) do
Developer.find(:all, :order => 'id')
end
assert !scoped_developers.include?(developers(:david))
@@ -1847,17 +1847,17 @@ class BasicsTest < ActiveRecord::TestCase
def test_scoped_find_order
# Test order in scope
- scoped_developers = Developer.with_scope(:find => { :limit => 1, :order => 'salary DESC' }) do
+ scoped_developers = Developer.send(:with_scope, :find => { :limit => 1, :order => 'salary DESC' }) do
Developer.find(:all)
end
assert_equal 'Jamis', scoped_developers.first.name
assert scoped_developers.include?(developers(:jamis))
# Test scope without order and order in find
- scoped_developers = Developer.with_scope(:find => { :limit => 1 }) do
+ scoped_developers = Developer.send(:with_scope, :find => { :limit => 1 }) do
Developer.find(:all, :order => 'salary DESC')
end
# Test scope order + find order, find has priority
- scoped_developers = Developer.with_scope(:find => { :limit => 3, :order => 'id DESC' }) do
+ scoped_developers = Developer.send(:with_scope, :find => { :limit => 3, :order => 'id DESC' }) do
Developer.find(:all, :order => 'salary ASC')
end
assert scoped_developers.include?(developers(:poor_jamis))
@@ -1869,7 +1869,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_scoped_find_limit_offset_including_has_many_association
- topics = Topic.with_scope(:find => {:limit => 1, :offset => 1, :include => :replies}) do
+ topics = Topic.send(:with_scope, :find => {:limit => 1, :offset => 1, :include => :replies}) do
Topic.find(:all, :order => "topics.id")
end
assert_equal 1, topics.size
@@ -1877,7 +1877,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_scoped_find_order_including_has_many_association
- developers = Developer.with_scope(:find => { :order => 'developers.salary DESC', :include => :projects }) do
+ developers = Developer.send(:with_scope, :find => { :order => 'developers.salary DESC', :include => :projects }) do
Developer.find(:all)
end
assert developers.size >= 2
@@ -1887,7 +1887,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_scoped_find_with_group_and_having
- developers = Developer.with_scope(:find => { :group => 'developers.salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do
+ developers = Developer.send(:with_scope, :find => { :group => 'developers.salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do
Developer.find(:all)
end
assert_equal 3, developers.size
@@ -1933,7 +1933,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_find_scoped_ordered_last
- last_developer = Developer.with_scope(:find => { :order => 'developers.salary ASC' }) do
+ last_developer = Developer.send(:with_scope, :find => { :order => 'developers.salary ASC' }) do
Developer.find(:last)
end
assert_equal last_developer, Developer.find(:all, :order => 'developers.salary ASC').last
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 004f4d0ea6..bd2d471fc7 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -29,8 +29,8 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_type_cast_calculated_value_should_convert_db_averages_of_fixnum_class_to_decimal
- assert_equal 0, NumericData.send(:type_cast_calculated_value, 0, nil, 'avg')
- assert_equal 53.0, NumericData.send(:type_cast_calculated_value, 53, nil, 'avg')
+ assert_equal 0, NumericData.scoped.send(:type_cast_calculated_value, 0, nil, 'avg')
+ assert_equal 53.0, NumericData.scoped.send(:type_cast_calculated_value, 53, nil, 'avg')
end
def test_should_get_maximum_of_field
@@ -42,7 +42,7 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_get_maximum_of_field_with_scoped_include
- Account.with_scope :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do
+ Account.send :with_scope, :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do
assert_equal 50, Account.maximum(:credit_limit)
end
end
@@ -248,17 +248,15 @@ class CalculationsTest < ActiveRecord::TestCase
def test_should_reject_invalid_options
assert_nothing_raised do
- [:count, :sum].each do |func|
- # empty options are valid
- Company.send(:validate_calculation_options, func)
- # these options are valid for all calculations
- [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
- Company.send(:validate_calculation_options, func, opt => true)
- end
+ # empty options are valid
+ Company.send(:validate_calculation_options)
+ # these options are valid for all calculations
+ [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
+ Company.send(:validate_calculation_options, opt => true)
end
# :include is only valid on :count
- Company.send(:validate_calculation_options, :count, :include => true)
+ Company.send(:validate_calculation_options, :include => true)
end
assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) }
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index c531a2dec1..d2451f24c1 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -120,7 +120,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_exists_with_scoped_include
- Developer.with_scope(:find => { :include => :projects, :order => "projects.name" }) do
+ Developer.send(:with_scope, :find => { :include => :projects, :order => "projects.name" }) do
assert Developer.exists?
end
end
@@ -1022,8 +1022,8 @@ class FinderTest < ActiveRecord::TestCase
def test_finder_with_scoped_from
all_topics = Topic.find(:all)
- Topic.with_scope(:find => { :from => 'fake_topics' }) do
- assert_equal all_topics, Topic.all(:from => 'topics').to_a
+ Topic.send(:with_scope, :find => { :from => 'fake_topics' }) do
+ assert_equal all_topics, Topic.from('topics').to_a
end
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 307320b964..479970b2fa 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -47,11 +47,6 @@ ActiveRecord::Base.connection.class.class_eval do
alias_method_chain :execute, :query_record
end
-# Make with_scope public for tests
-class << ActiveRecord::Base
- public :with_scope, :with_exclusive_scope
-end
-
unless ENV['FIXTURE_DEBUG']
module ActiveRecord::TestFixtures::ClassMethods
def try_to_load_dependency_with_silence(*args)
@@ -62,9 +57,10 @@ unless ENV['FIXTURE_DEBUG']
end
end
+require "cases/validations_repair_helper"
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
- include ActiveModel::ValidationsRepairHelper
+ include ActiveRecord::ValidationsRepairHelper
self.fixture_path = FIXTURES_ROOT
self.use_instantiated_fixtures = false
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index a64c01292f..dfaecf35cf 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -225,7 +225,7 @@ unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter)
def test_sane_find_with_scoped_lock
assert_nothing_raised do
Person.transaction do
- Person.with_scope(:find => { :lock => true }) do
+ Person.send(:with_scope, :find => { :lock => true }) do
Person.find 1
end
end
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index eb4ce0e774..cfc6f8772c 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -10,19 +10,19 @@ class MethodScopingTest < ActiveRecord::TestCase
fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects
def test_set_conditions
- Developer.with_scope(:find => { :conditions => 'just a test...' }) do
+ Developer.send(:with_scope, :find => { :conditions => 'just a test...' }) do
assert_equal 'just a test...', Developer.send(:current_scoped_methods)[:find][:conditions]
end
end
def test_scoped_find
- Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
assert_nothing_raised { Developer.find(1) }
end
end
def test_scoped_find_first
- Developer.with_scope(:find => { :conditions => "salary = 100000" }) do
+ Developer.send(:with_scope, :find => { :conditions => "salary = 100000" }) do
assert_equal Developer.find(10), Developer.find(:first, :order => 'name')
end
end
@@ -30,7 +30,7 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_scoped_find_last
highest_salary = Developer.find(:first, :order => "salary DESC")
- Developer.with_scope(:find => { :order => "salary" }) do
+ Developer.send(:with_scope, :find => { :order => "salary" }) do
assert_equal highest_salary, Developer.last
end
end
@@ -39,38 +39,38 @@ class MethodScopingTest < ActiveRecord::TestCase
lowest_salary = Developer.find(:first, :order => "salary ASC")
highest_salary = Developer.find(:first, :order => "salary DESC")
- Developer.with_scope(:find => { :order => "salary" }) do
+ Developer.send(:with_scope, :find => { :order => "salary" }) do
assert_equal highest_salary, Developer.last
assert_equal lowest_salary, Developer.first
end
end
def test_scoped_find_combines_conditions
- Developer.with_scope(:find => { :conditions => "salary = 9000" }) do
+ Developer.send(:with_scope, :find => { :conditions => "salary = 9000" }) do
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => "name = 'Jamis'")
end
end
def test_scoped_find_sanitizes_conditions
- Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
+ Developer.send(:with_scope, :find => { :conditions => ['salary = ?', 9000] }) do
assert_equal developers(:poor_jamis), Developer.find(:first)
end
end
def test_scoped_find_combines_and_sanitizes_conditions
- Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
+ Developer.send(:with_scope, :find => { :conditions => ['salary = ?', 9000] }) do
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
end
end
def test_scoped_find_all
- Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
assert_equal [developers(:david)], Developer.find(:all)
end
end
def test_scoped_find_select
- Developer.with_scope(:find => { :select => "id, name" }) do
+ Developer.send(:with_scope, :find => { :select => "id, name" }) do
developer = Developer.find(:first, :conditions => "name = 'David'")
assert_equal "David", developer.name
assert !developer.has_attribute?(:salary)
@@ -78,7 +78,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_options_select_replaces_scope_select
- Developer.with_scope(:find => { :select => "id, name" }) do
+ Developer.send(:with_scope, :find => { :select => "id, name" }) do
developer = Developer.find(:first, :select => 'id, salary', :conditions => "name = 'David'")
assert_equal 80000, developer.salary
assert !developer.has_attribute?(:name)
@@ -86,11 +86,11 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_count
- Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
assert_equal 1, Developer.count
end
- Developer.with_scope(:find => { :conditions => 'salary = 100000' }) do
+ Developer.send(:with_scope, :find => { :conditions => 'salary = 100000' }) do
assert_equal 8, Developer.count
assert_equal 1, Developer.count(:conditions => "name LIKE 'fixture_1%'")
end
@@ -98,7 +98,7 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_scoped_find_include
# with the include, will retrieve only developers for the given project
- scoped_developers = Developer.with_scope(:find => { :include => :projects }) do
+ scoped_developers = Developer.send(:with_scope, :find => { :include => :projects }) do
Developer.find(:all, :conditions => 'projects.id = 2')
end
assert scoped_developers.include?(developers(:david))
@@ -107,7 +107,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_joins
- scoped_developers = Developer.with_scope(:find => { :joins => 'JOIN developers_projects ON id = developer_id' } ) do
+ scoped_developers = Developer.send(:with_scope, :find => { :joins => 'JOIN developers_projects ON id = developer_id' } ) do
Developer.find(:all, :conditions => 'developers_projects.project_id = 2')
end
assert scoped_developers.include?(developers(:david))
@@ -117,7 +117,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_using_new_style_joins
- scoped_developers = Developer.with_scope(:find => { :joins => :projects }) do
+ scoped_developers = Developer.send(:with_scope, :find => { :joins => :projects }) do
Developer.find(:all, :conditions => 'projects.id = 2')
end
assert scoped_developers.include?(developers(:david))
@@ -127,7 +127,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_merges_old_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id ' }) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id ' }) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
end
assert scoped_authors.include?(authors(:david))
@@ -137,7 +137,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_merges_new_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => :comments, :conditions => 'comments.id = 1')
end
assert scoped_authors.include?(authors(:david))
@@ -147,7 +147,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_merges_new_and_old_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
end
assert scoped_authors.include?(authors(:david))
@@ -157,7 +157,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_merges_string_array_style_and_string_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => ["INNER JOIN posts ON posts.author_id = authors.id"]}) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => ["INNER JOIN posts ON posts.author_id = authors.id"]}) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
end
assert scoped_authors.include?(authors(:david))
@@ -167,7 +167,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_merges_string_array_style_and_hash_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => :posts}) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => :posts}) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => ['INNER JOIN comments ON posts.id = comments.post_id'], :conditions => 'comments.id = 1')
end
assert scoped_authors.include?(authors(:david))
@@ -177,7 +177,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_merges_joins_and_eliminates_duplicate_string_joins
- scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON posts.author_id = authors.id'}) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => 'INNER JOIN posts ON posts.author_id = authors.id'}) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => ["INNER JOIN posts ON posts.author_id = authors.id", "INNER JOIN comments ON posts.id = comments.post_id"], :conditions => 'comments.id = 1')
end
assert scoped_authors.include?(authors(:david))
@@ -187,7 +187,7 @@ class MethodScopingTest < ActiveRecord::TestCase
end
def test_scoped_find_strips_spaces_from_string_joins_and_eliminates_duplicate_string_joins
- scoped_authors = Author.with_scope(:find => { :joins => ' INNER JOIN posts ON posts.author_id = authors.id '}) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => ' INNER JOIN posts ON posts.author_id = authors.id '}) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => ['INNER JOIN posts ON posts.author_id = authors.id'], :conditions => 'posts.id = 1')
end
assert scoped_authors.include?(authors(:david))
@@ -198,7 +198,7 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_scoped_count_include
# with the include, will retrieve only developers for the given project
- Developer.with_scope(:find => { :include => :projects }) do
+ Developer.send(:with_scope, :find => { :include => :projects }) do
assert_equal 1, Developer.count(:conditions => 'projects.id = 2')
end
end
@@ -206,7 +206,7 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_scoped_create
new_comment = nil
- VerySpecialComment.with_scope(:create => { :post_id => 1 }) do
+ VerySpecialComment.send(:with_scope, :create => { :post_id => 1 }) do
assert_equal({ :post_id => 1 }, VerySpecialComment.send(:current_scoped_methods)[:create])
new_comment = VerySpecialComment.create :body => "Wonderful world"
end
@@ -216,14 +216,14 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_immutable_scope
options = { :conditions => "name = 'David'" }
- Developer.with_scope(:find => options) do
+ Developer.send(:with_scope, :find => options) do
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
options[:conditions] = "name != 'David'"
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
end
scope = { :find => { :conditions => "name = 'David'" }}
- Developer.with_scope(scope) do
+ Developer.send(:with_scope, scope) do
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
scope[:find][:conditions] = "name != 'David'"
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
@@ -232,7 +232,7 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_scoped_with_duck_typing
scoping = Struct.new(:method_scoping).new(:find => { :conditions => ["name = ?", 'David'] })
- Developer.with_scope(scoping) do
+ Developer.send(:with_scope, scoping) do
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
end
end
@@ -241,7 +241,7 @@ class MethodScopingTest < ActiveRecord::TestCase
scoped_methods = Developer.instance_eval('current_scoped_methods')
begin
- Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'Jamis'" }) do
raise "an exception"
end
rescue
@@ -254,8 +254,8 @@ class NestedScopingTest < ActiveRecord::TestCase
fixtures :authors, :developers, :projects, :comments, :posts
def test_merge_options
- Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
- Developer.with_scope(:find => { :limit => 10 }) do
+ Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do
+ Developer.send(:with_scope, :find => { :limit => 10 }) do
merged_option = Developer.instance_eval('current_scoped_methods')[:find]
assert_equal({ :conditions => 'salary = 80000', :limit => 10 }, merged_option)
end
@@ -263,8 +263,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_merge_inner_scope_has_priority
- Developer.with_scope(:find => { :limit => 5 }) do
- Developer.with_scope(:find => { :limit => 10 }) do
+ Developer.send(:with_scope, :find => { :limit => 5 }) do
+ Developer.send(:with_scope, :find => { :limit => 10 }) do
merged_option = Developer.instance_eval('current_scoped_methods')[:find]
assert_equal({ :limit => 10 }, merged_option)
end
@@ -272,8 +272,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_replace_options
- Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
- Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_exclusive_scope, :find => { :conditions => "name = 'Jamis'" }) do
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.instance_eval('current_scoped_methods'))
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.send(:scoped_methods)[-1])
end
@@ -281,21 +281,21 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_append_conditions
- Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
- Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do
appended_condition = Developer.instance_eval('current_scoped_methods')[:find][:conditions]
assert_equal("(name = 'David') AND (salary = 80000)", appended_condition)
assert_equal(1, Developer.count)
end
- Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'Maiha'" }) do
assert_equal(0, Developer.count)
end
end
end
def test_merge_and_append_options
- Developer.with_scope(:find => { :conditions => 'salary = 80000', :limit => 10 }) do
- Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_scope, :find => { :conditions => 'salary = 80000', :limit => 10 }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
merged_option = Developer.instance_eval('current_scoped_methods')[:find]
assert_equal({ :conditions => "(salary = 80000) AND (name = 'David')", :limit => 10 }, merged_option)
end
@@ -303,8 +303,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_nested_scoped_find
- Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
- Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'Jamis'" }) do
+ Developer.send(:with_exclusive_scope, :find => { :conditions => "name = 'David'" }) do
assert_nothing_raised { Developer.find(1) }
assert_equal('David', Developer.find(:first).name)
end
@@ -313,8 +313,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_nested_scoped_find_include
- Developer.with_scope(:find => { :include => :projects }) do
- Developer.with_scope(:find => { :conditions => "projects.id = 2" }) do
+ Developer.send(:with_scope, :find => { :include => :projects }) do
+ Developer.send(:with_scope, :find => { :conditions => "projects.id = 2" }) do
assert_nothing_raised { Developer.find(1) }
assert_equal('David', Developer.find(:first).name)
end
@@ -323,24 +323,24 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_nested_scoped_find_merged_include
# :include's remain unique and don't "double up" when merging
- Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
- Developer.with_scope(:find => { :include => :projects }) do
+ Developer.send(:with_scope, :find => { :include => :projects, :conditions => "projects.id = 2" }) do
+ Developer.send(:with_scope, :find => { :include => :projects }) do
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
assert_equal('David', Developer.find(:first).name)
end
end
# the nested scope doesn't remove the first :include
- Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
- Developer.with_scope(:find => { :include => [] }) do
+ Developer.send(:with_scope, :find => { :include => :projects, :conditions => "projects.id = 2" }) do
+ Developer.send(:with_scope, :find => { :include => [] }) do
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
assert_equal('David', Developer.find(:first).name)
end
end
# mixing array and symbol include's will merge correctly
- Developer.with_scope(:find => { :include => [:projects], :conditions => "projects.id = 2" }) do
- Developer.with_scope(:find => { :include => :projects }) do
+ Developer.send(:with_scope, :find => { :include => [:projects], :conditions => "projects.id = 2" }) do
+ Developer.send(:with_scope, :find => { :include => :projects }) do
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
assert_equal('David', Developer.find(:first).name)
end
@@ -348,21 +348,21 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_nested_scoped_find_replace_include
- Developer.with_scope(:find => { :include => :projects }) do
- Developer.with_exclusive_scope(:find => { :include => [] }) do
+ Developer.send(:with_scope, :find => { :include => :projects }) do
+ Developer.send(:with_exclusive_scope, :find => { :include => [] }) do
assert_equal 0, Developer.instance_eval('current_scoped_methods')[:find][:include].length
end
end
end
def test_three_level_nested_exclusive_scoped_find
- Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'Jamis'" }) do
assert_equal('Jamis', Developer.find(:first).name)
- Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_exclusive_scope, :find => { :conditions => "name = 'David'" }) do
assert_equal('David', Developer.find(:first).name)
- Developer.with_exclusive_scope(:find => { :conditions => "name = 'Maiha'" }) do
+ Developer.send(:with_exclusive_scope, :find => { :conditions => "name = 'Maiha'" }) do
assert_equal(nil, Developer.find(:first))
end
@@ -377,8 +377,8 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_merged_scoped_find
poor_jamis = developers(:poor_jamis)
- Developer.with_scope(:find => { :conditions => "salary < 100000" }) do
- Developer.with_scope(:find => { :offset => 1, :order => 'id asc' }) do
+ Developer.send(:with_scope, :find => { :conditions => "salary < 100000" }) do
+ Developer.send(:with_scope, :find => { :offset => 1, :order => 'id asc' }) do
# Oracle adapter does not generated space after asc therefore trailing space removed from regex
assert_sql /ORDER BY id asc/ do
assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
@@ -388,16 +388,16 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_merged_scoped_find_sanitizes_conditions
- Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
- Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
+ Developer.send(:with_scope, :find => { :conditions => ["name = ?", 'David'] }) do
+ Developer.send(:with_scope, :find => { :conditions => ['salary = ?', 9000] }) do
assert_raise(ActiveRecord::RecordNotFound) { developers(:poor_jamis) }
end
end
end
def test_nested_scoped_find_combines_and_sanitizes_conditions
- Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
- Developer.with_exclusive_scope(:find => { :conditions => ['salary = ?', 9000] }) do
+ Developer.send(:with_scope, :find => { :conditions => ["name = ?", 'David'] }) do
+ Developer.send(:with_exclusive_scope, :find => { :conditions => ['salary = ?', 9000] }) do
assert_equal developers(:poor_jamis), Developer.find(:first)
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
end
@@ -405,8 +405,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_merged_scoped_find_combines_and_sanitizes_conditions
- Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
- Developer.with_scope(:find => { :conditions => ['salary > ?', 9000] }) do
+ Developer.send(:with_scope, :find => { :conditions => ["name = ?", 'David'] }) do
+ Developer.send(:with_scope, :find => { :conditions => ['salary > ?', 9000] }) do
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
end
end
@@ -414,8 +414,8 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_nested_scoped_create
comment = nil
- Comment.with_scope(:create => { :post_id => 1}) do
- Comment.with_scope(:create => { :post_id => 2}) do
+ Comment.send(:with_scope, :create => { :post_id => 1}) do
+ Comment.send(:with_scope, :create => { :post_id => 2}) do
assert_equal({ :post_id => 2 }, Comment.send(:current_scoped_methods)[:create])
comment = Comment.create :body => "Hey guys, nested scopes are broken. Please fix!"
end
@@ -425,8 +425,8 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_nested_exclusive_scope_for_create
comment = nil
- Comment.with_scope(:create => { :body => "Hey guys, nested scopes are broken. Please fix!" }) do
- Comment.with_exclusive_scope(:create => { :post_id => 1 }) do
+ Comment.send(:with_scope, :create => { :body => "Hey guys, nested scopes are broken. Please fix!" }) do
+ Comment.send(:with_exclusive_scope, :create => { :post_id => 1 }) do
assert_equal({ :post_id => 1 }, Comment.send(:current_scoped_methods)[:create])
comment = Comment.create :body => "Hey guys"
end
@@ -437,8 +437,8 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_merged_scoped_find_on_blank_conditions
[nil, " ", [], {}].each do |blank|
- Developer.with_scope(:find => {:conditions => blank}) do
- Developer.with_scope(:find => {:conditions => blank}) do
+ Developer.send(:with_scope, :find => {:conditions => blank}) do
+ Developer.send(:with_scope, :find => {:conditions => blank}) do
assert_nothing_raised { Developer.find(:first) }
end
end
@@ -447,8 +447,8 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_merged_scoped_find_on_blank_bind_conditions
[ [""], ["",{}] ].each do |blank|
- Developer.with_scope(:find => {:conditions => blank}) do
- Developer.with_scope(:find => {:conditions => blank}) do
+ Developer.send(:with_scope, :find => {:conditions => blank}) do
+ Developer.send(:with_scope, :find => {:conditions => blank}) do
assert_nothing_raised { Developer.find(:first) }
end
end
@@ -458,8 +458,8 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_immutable_nested_scope
options1 = { :conditions => "name = 'Jamis'" }
options2 = { :conditions => "name = 'David'" }
- Developer.with_scope(:find => options1) do
- Developer.with_exclusive_scope(:find => options2) do
+ Developer.send(:with_scope, :find => options1) do
+ Developer.send(:with_exclusive_scope, :find => options2) do
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
options1[:conditions] = options2[:conditions] = nil
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
@@ -470,8 +470,8 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_immutable_merged_scope
options1 = { :conditions => "name = 'Jamis'" }
options2 = { :conditions => "salary > 10000" }
- Developer.with_scope(:find => options1) do
- Developer.with_scope(:find => options2) do
+ Developer.send(:with_scope, :find => options1) do
+ Developer.send(:with_scope, :find => options2) do
assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
options1[:conditions] = options2[:conditions] = nil
assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
@@ -480,10 +480,10 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_ensure_that_method_scoping_is_correctly_restored
- Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
scoped_methods = Developer.instance_eval('current_scoped_methods')
begin
- Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
+ Developer.send(:with_scope, :find => { :conditions => "name = 'Maiha'" }) do
raise "an exception"
end
rescue
@@ -493,8 +493,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_nested_scoped_find_merges_old_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id' }) do
- Author.with_scope(:find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id' }) do
+ Author.send(:with_scope, :find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1')
end
end
@@ -505,8 +505,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_nested_scoped_find_merges_new_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
- Author.with_scope(:find => { :joins => :comments }) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
+ Author.send(:with_scope, :find => { :joins => :comments }) do
Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1')
end
end
@@ -517,8 +517,8 @@ class NestedScopingTest < ActiveRecord::TestCase
end
def test_nested_scoped_find_merges_new_and_old_style_joins
- scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
- Author.with_scope(:find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
+ scoped_authors = Author.send(:with_scope, :find => { :joins => :posts }) do
+ Author.send(:with_scope, :find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
Author.find(:all, :select => 'DISTINCT authors.*', :joins => '', :conditions => 'comments.id = 1')
end
end
@@ -552,7 +552,7 @@ class HasManyScopingTest< ActiveRecord::TestCase
end
def test_nested_scope
- Comment.with_scope(:find => { :conditions => '1=1' }) do
+ Comment.send(:with_scope, :find => { :conditions => '1=1' }) do
assert_equal 'a comment...', @welcome.comments.what_are_you
end
end
@@ -577,7 +577,7 @@ class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase
end
def test_nested_scope
- Category.with_scope(:find => { :conditions => '1=1' }) do
+ Category.send(:with_scope, :find => { :conditions => '1=1' }) do
assert_equal 'a comment...', @welcome.comments.what_are_you
end
end
@@ -633,7 +633,7 @@ class DefaultScopingTest < ActiveRecord::TestCase
def test_nested_scope
expected = Developer.find(:all, :order => 'name DESC').collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.with_scope(:find => { :order => 'name DESC'}) do
+ received = DeveloperOrderedBySalary.send(:with_scope, :find => { :order => 'name DESC'}) do
DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
end
assert_equal expected, received
@@ -647,7 +647,7 @@ class DefaultScopingTest < ActiveRecord::TestCase
def test_nested_exclusive_scope
expected = Developer.find(:all, :limit => 100).collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.with_exclusive_scope(:find => { :limit => 100 }) do
+ received = DeveloperOrderedBySalary.send(:with_exclusive_scope, :find => { :limit => 100 }) do
DeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
end
assert_equal expected, received
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index 53fd168e1b..60c5bad225 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -245,6 +245,27 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
def test_should_automatically_enable_autosave_on_the_association
assert Pirate.reflect_on_association(:ship).options[:autosave]
end
+
+ def test_should_accept_update_only_option
+ @pirate.update_attribute(:update_only_ship_attributes, { :id => @pirate.ship.id, :name => 'Mayflower' })
+ end
+
+ def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true
+ @ship.delete
+ assert_difference('Ship.count', 1) do
+ @pirate.reload.update_attribute(:update_only_ship_attributes, { :name => 'Mayflower' })
+ end
+ end
+
+ def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
+ @ship.delete
+ @ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
+
+ assert_no_difference('Ship.count') do
+ @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower' })
+ end
+ assert_equal 'Mayflower', @ship.reload.name
+ end
end
class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
@@ -362,6 +383,27 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
def test_should_automatically_enable_autosave_on_the_association
assert Ship.reflect_on_association(:pirate).options[:autosave]
end
+
+ def test_should_accept_update_only_option
+ @ship.update_attribute(:update_only_pirate_attributes, { :id => @pirate.ship.id, :catchphrase => 'Arr' })
+ end
+
+ def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true
+ @pirate.delete
+ assert_difference('Pirate.count', 1) do
+ @ship.reload.update_attribute(:update_only_pirate_attributes, { :catchphrase => 'Arr' })
+ end
+ end
+
+ def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
+ @pirate.delete
+ @pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
+
+ assert_no_difference('Pirate.count') do
+ @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr' })
+ end
+ assert_equal 'Arr', @pirate.reload.catchphrase
+ end
end
module NestedAttributesOnACollectionAssociationTests
@@ -371,6 +413,15 @@ module NestedAttributesOnACollectionAssociationTests
assert_respond_to @pirate, association_setter
end
+ def test_should_save_only_one_association_on_create
+ pirate = Pirate.create!({
+ :catchphrase => 'Arr',
+ association_getter => { 'foo' => { :name => 'Grace OMalley' } }
+ })
+
+ assert_equal 1, pirate.reload.send(@association_name).count
+ end
+
def test_should_take_a_hash_with_string_keys_and_assign_the_attributes_to_the_associated_models
@alternate_params[association_getter].stringify_keys!
@pirate.update_attributes @alternate_params
diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb
index b921cbdc9c..98011f40a4 100644
--- a/activerecord/test/cases/readonly_test.rb
+++ b/activerecord/test/cases/readonly_test.rb
@@ -33,19 +33,20 @@ class ReadOnlyTest < ActiveRecord::TestCase
def test_find_with_readonly_option
Developer.find(:all).each { |d| assert !d.readonly? }
- Developer.find(:all, :readonly => false).each { |d| assert !d.readonly? }
- Developer.find(:all, :readonly => true).each { |d| assert d.readonly? }
+ Developer.readonly(false).each { |d| assert !d.readonly? }
+ Developer.readonly(true).each { |d| assert d.readonly? }
+ Developer.readonly.each { |d| assert d.readonly? }
end
def test_find_with_joins_option_implies_readonly
# Blank joins don't count.
- Developer.find(:all, :joins => ' ').each { |d| assert !d.readonly? }
- Developer.find(:all, :joins => ' ', :readonly => false).each { |d| assert !d.readonly? }
+ Developer.joins(' ').each { |d| assert !d.readonly? }
+ Developer.joins(' ').readonly(false).each { |d| assert !d.readonly? }
# Others do.
- Developer.find(:all, :joins => ', projects').each { |d| assert d.readonly? }
- Developer.find(:all, :joins => ', projects', :readonly => false).each { |d| assert !d.readonly? }
+ Developer.joins(', projects').each { |d| assert d.readonly? }
+ Developer.joins(', projects').readonly(false).each { |d| assert !d.readonly? }
end
@@ -54,7 +55,7 @@ class ReadOnlyTest < ActiveRecord::TestCase
assert !dev.projects.empty?
assert dev.projects.all?(&:readonly?)
assert dev.projects.find(:all).all?(&:readonly?)
- assert dev.projects.find(:all, :readonly => true).all?(&:readonly?)
+ assert dev.projects.readonly(true).all?(&:readonly?)
end
def test_has_many_find_readonly
@@ -62,7 +63,7 @@ class ReadOnlyTest < ActiveRecord::TestCase
assert !post.comments.empty?
assert !post.comments.any?(&:readonly?)
assert !post.comments.find(:all).any?(&:readonly?)
- assert post.comments.find(:all, :readonly => true).all?(&:readonly?)
+ assert post.comments.readonly(true).all?(&:readonly?)
end
def test_has_many_with_through_is_not_implicitly_marked_readonly
@@ -71,32 +72,32 @@ class ReadOnlyTest < ActiveRecord::TestCase
end
def test_readonly_scoping
- Post.with_scope(:find => { :conditions => '1=1' }) do
+ Post.send(:with_scope, :find => { :conditions => '1=1' }) do
assert !Post.find(1).readonly?
- assert Post.find(1, :readonly => true).readonly?
- assert !Post.find(1, :readonly => false).readonly?
+ assert Post.readonly(true).find(1).readonly?
+ assert !Post.readonly(false).find(1).readonly?
end
- Post.with_scope(:find => { :joins => ' ' }) do
+ Post.send(:with_scope, :find => { :joins => ' ' }) do
assert !Post.find(1).readonly?
- assert Post.find(1, :readonly => true).readonly?
- assert !Post.find(1, :readonly => false).readonly?
+ assert Post.readonly.find(1).readonly?
+ assert !Post.readonly(false).find(1).readonly?
end
# Oracle barfs on this because the join includes unqualified and
# conflicting column names
unless current_adapter?(:OracleAdapter)
- Post.with_scope(:find => { :joins => ', developers' }) do
+ Post.send(:with_scope, :find => { :joins => ', developers' }) do
assert Post.find(1).readonly?
- assert Post.find(1, :readonly => true).readonly?
- assert !Post.find(1, :readonly => false).readonly?
+ assert Post.readonly.find(1).readonly?
+ assert !Post.readonly(false).find(1).readonly?
end
end
- Post.with_scope(:find => { :readonly => true }) do
+ Post.send(:with_scope, :find => { :readonly => true }) do
assert Post.find(1).readonly?
- assert Post.find(1, :readonly => true).readonly?
- assert !Post.find(1, :readonly => false).readonly?
+ assert Post.readonly.find(1).readonly?
+ assert !Post.readonly(false).find(1).readonly?
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 9c5a38a399..f0ef3e22c5 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -38,7 +38,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_scoped_first
- topics = Topic.scoped
+ topics = Topic.scoped.order('id ASC')
assert_queries(1) do
2.times { assert_equal "The First Topic", topics.first.title }
@@ -48,7 +48,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_loaded_first
- topics = Topic.scoped
+ topics = Topic.scoped.order('id ASC')
assert_queries(1) do
topics.all # force load
@@ -81,7 +81,7 @@ class RelationTest < ActiveRecord::TestCase
def test_finding_with_order
topics = Topic.order('id')
- assert_equal 4, topics.size
+ assert_equal 4, topics.to_a.size
assert_equal topics(:first).title, topics.first.title
end
@@ -95,11 +95,11 @@ class RelationTest < ActiveRecord::TestCase
def test_finding_with_order_limit_and_offset
entrants = Entrant.order("id ASC").limit(2).offset(1)
- assert_equal 2, entrants.size
+ assert_equal 2, entrants.to_a.size
assert_equal entrants(:second).name, entrants.first.name
entrants = Entrant.order("id ASC").limit(2).offset(2)
- assert_equal 1, entrants.size
+ assert_equal 1, entrants.to_a.size
assert_equal entrants(:third).name, entrants.first.name
end
@@ -142,7 +142,22 @@ class RelationTest < ActiveRecord::TestCase
relation = Topic.scoped
["map", "uniq", "sort", "insert", "delete", "update"].each do |method|
- assert relation.respond_to?(method), "Topic.all should respond to #{method.inspect}"
+ assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}"
+ end
+ end
+
+ def test_respond_to_private_arel_methods
+ relation = Topic.scoped
+
+ assert ! relation.respond_to?(:matching_attributes)
+ assert relation.respond_to?(:matching_attributes, true)
+ end
+
+ def test_respond_to_dynamic_finders
+ relation = Topic.scoped
+
+ ["find_by_title", "find_by_title_and_author_name", "find_or_create_by_title", "find_or_initialize_by_title_and_author_name"].each do |method|
+ assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}"
end
end
@@ -244,7 +259,7 @@ class RelationTest < ActiveRecord::TestCase
author = Author.scoped.find_by_id!(authors(:david).id)
assert_equal "David", author.name
- assert_raises(ActiveRecord::RecordNotFound) { Author.scoped.find_by_id_and_name!('invalid', 'wt') }
+ assert_raises(ActiveRecord::RecordNotFound) { Author.scoped.find_by_id_and_name!(20, 'invalid') }
end
def test_dynamic_find_all_by_attributes
@@ -281,7 +296,7 @@ class RelationTest < ActiveRecord::TestCase
david = authors.find(authors(:david).id)
assert_equal 'David', david.name
- assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('invalid') }
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('42') }
end
def test_find_ids
@@ -294,8 +309,140 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'Mary', results[1].name
assert_equal results, authors.find([authors(:david).id, authors(:mary).id])
- assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, 'invalid') }
- assert_raises(ActiveRecord::RecordNotFound) { authors.find(['invalid', 'oops']) }
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, '42') }
+ assert_raises(ActiveRecord::RecordNotFound) { authors.find(['42', 43]) }
+ end
+
+ def test_exists
+ davids = Author.where(:name => 'David')
+ assert davids.exists?
+ assert davids.exists?(authors(:david).id)
+ assert ! davids.exists?(authors(:mary).id)
+ assert ! davids.exists?("42")
+ assert ! davids.exists?(42)
+
+ fake = Author.where(:name => 'fake author')
+ assert ! fake.exists?
+ assert ! fake.exists?(authors(:david).id)
+ end
+
+ def test_last
+ authors = Author.scoped
+ assert_equal authors(:mary), authors.last
+ end
+
+ def test_destroy_all
+ davids = Author.where(:name => 'David')
+
+ # Force load
+ assert_equal [authors(:david)], davids.to_a
+ assert davids.loaded?
+
+ assert_difference('Author.count', -1) { davids.destroy_all }
+
+ assert_equal [], davids.to_a
+ assert davids.loaded?
+ end
+
+ def test_delete_all
+ davids = Author.where(:name => 'David')
+
+ assert_difference('Author.count', -1) { davids.delete_all }
+ assert ! davids.loaded?
+ end
+
+ def test_delete_all_loaded
+ davids = Author.where(:name => 'David')
+
+ # Force load
+ assert_equal [authors(:david)], davids.to_a
+ assert davids.loaded?
+
+ assert_difference('Author.count', -1) { davids.delete_all }
+
+ assert_equal [], davids.to_a
+ assert davids.loaded?
+ end
+
+ def test_relation_merging
+ devs = Developer.where("salary >= 80000") & Developer.limit(2) & Developer.order('id ASC').where("id < 3")
+ assert_equal [developers(:david), developers(:jamis)], devs.to_a
+
+ dev_with_count = Developer.limit(1) & Developer.order('id DESC') & Developer.select('developers.*')
+ assert_equal [developers(:poor_jamis)], dev_with_count.to_a
+ end
+
+ def test_relation_merging_with_eager_load
+ relations = []
+ relations << (Post.order('comments.id DESC') & Post.eager_load(:last_comment) & Post.scoped)
+ relations << (Post.eager_load(:last_comment) & Post.order('comments.id DESC') & Post.scoped)
+
+ relations.each do |posts|
+ post = posts.find { |p| p.id == 1 }
+ assert_equal Post.find(1).last_comment, post.last_comment
+ end
+ end
+
+ def test_relation_merging_with_preload
+ [Post.scoped & Post.preload(:author), Post.preload(:author) & Post.scoped].each do |posts|
+ assert_queries(2) { assert posts.first.author }
+ end
+ end
+
+ def test_invalid_merge
+ assert_raises(ArgumentError) { Post.scoped & Developer.scoped }
+ end
+
+ def test_count
+ posts = Post.scoped
+
+ assert_equal 7, posts.count
+ assert_equal 7, posts.count(:all)
+ assert_equal 7, posts.count(:id)
+
+ assert_equal 1, posts.where('comments_count > 1').count
+ assert_equal 5, posts.where(:comments_count => 0).count
+ end
+
+ def test_count_with_distinct
+ posts = Post.scoped
+
+ assert_equal 3, posts.count(:comments_count, :distinct => true)
+ assert_equal 7, posts.count(:comments_count, :distinct => false)
+
+ assert_equal 3, posts.select(:comments_count).count(:distinct => true)
+ assert_equal 7, posts.select(:comments_count).count(:distinct => false)
+ end
+
+ def test_count_explicit_columns
+ Post.update_all(:comments_count => nil)
+ posts = Post.scoped
+
+ assert_equal 0, posts.select('comments_count').where('id is not null').order('id').count
+ assert_equal 0, posts.where('id is not null').select('comments_count').count
+
+ assert_equal 7, posts.select('comments_count').count('id')
+ assert_equal 0, posts.select('comments_count').count
+ assert_equal 0, posts.count(:comments_count)
+ assert_equal 0, posts.count('comments_count')
+ end
+
+ def test_size
+ posts = Post.scoped
+
+ assert_queries(1) { assert_equal 7, posts.size }
+ assert ! posts.loaded?
+
+ best_posts = posts.where(:comments_count => 0)
+ best_posts.to_a # force load
+ assert_no_queries { assert_equal 5, best_posts.size }
+ end
+
+ def test_count_complex_chained_relations
+ posts = Post.select('comments_count').where('id is not null').group("author_id").where("comments_count > 0")
+
+ expected = { 1 => 2 }
+ assert_equal expected, posts.count
end
end
diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb
index 17ba4e2f8a..db633339f3 100644
--- a/activerecord/test/cases/validations/uniqueness_validation_test.rb
+++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb
@@ -213,7 +213,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase
def test_validates_uniqueness_inside_with_scope
Topic.validates_uniqueness_of(:title)
- Topic.with_scope(:find => { :conditions => { :author_name => "David" } }) do
+ Topic.send(:with_scope, :find => { :conditions => { :author_name => "David" } }) do
t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary")
assert t1.save
t2 = Topic.new("title" => "I'm unique!", "author_name" => "David")
diff --git a/activerecord/test/cases/validations_repair_helper.rb b/activerecord/test/cases/validations_repair_helper.rb
new file mode 100644
index 0000000000..e04738d209
--- /dev/null
+++ b/activerecord/test/cases/validations_repair_helper.rb
@@ -0,0 +1,35 @@
+module ActiveRecord
+ module ValidationsRepairHelper
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def repair_validations(*model_classes)
+ setup do
+ @_stored_callbacks = {}
+ model_classes.each do |k|
+ @_stored_callbacks[k] = k._validate_callbacks.dup
+ end
+ end
+ teardown do
+ model_classes.each do |k|
+ k._validate_callbacks = @_stored_callbacks[k]
+ k.__update_callbacks(:validate)
+ end
+ end
+ end
+ end
+
+ def repair_validations(*model_classes, &block)
+ @__stored_callbacks = {}
+ model_classes.each do |k|
+ @__stored_callbacks[k] = k._validate_callbacks.dup
+ end
+ return block.call
+ ensure
+ model_classes.each do |k|
+ k._validate_callbacks = @__stored_callbacks[k]
+ k.__update_callbacks(:validate)
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb
index 130231c622..7462d944e0 100644
--- a/activerecord/test/cases/validations_test.rb
+++ b/activerecord/test/cases/validations_test.rb
@@ -98,14 +98,14 @@ class ValidationsTest < ActiveRecord::TestCase
end
def test_scoped_create_without_attributes
- Reply.with_scope(:create => {}) do
+ Reply.send(:with_scope, :create => {}) do
assert_raise(ActiveRecord::RecordInvalid) { Reply.create! }
end
end
def test_create_with_exceptions_using_scope_for_protected_attributes
assert_nothing_raised do
- ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
+ ProtectedPerson.send(:with_scope, :create => { :first_name => "Mary" } ) do
person = ProtectedPerson.create! :addon => "Addon"
assert_equal person.first_name, "Mary", "scope should ignore attr_protected"
end
@@ -114,7 +114,7 @@ class ValidationsTest < ActiveRecord::TestCase
def test_create_with_exceptions_using_scope_and_empty_attributes
assert_nothing_raised do
- ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
+ ProtectedPerson.send(:with_scope, :create => { :first_name => "Mary" } ) do
person = ProtectedPerson.create!
assert_equal person.first_name, "Mary", "should be ok when no attributes are passed to create!"
end