diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2010-01-04 03:24:39 +0530 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2010-01-04 03:24:39 +0530 |
commit | cda36a0731f14b33a920bf7e32255661e06f890a (patch) | |
tree | 79ccba37953f9fe3055503be42b1610faa6d64ad /activerecord/test | |
parent | bd4a3cce4ecd8e648179a91e26506e3622ac2162 (diff) | |
parent | a115b5d79a850bb56cd3c9db9a05d6da35e3d7be (diff) | |
download | rails-cda36a0731f14b33a920bf7e32255661e06f890a.tar.gz rails-cda36a0731f14b33a920bf7e32255661e06f890a.tar.bz2 rails-cda36a0731f14b33a920bf7e32255661e06f890a.zip |
Merge remote branch 'mainstream/master'
Diffstat (limited to 'activerecord/test')
39 files changed, 1184 insertions, 378 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/habtm_join_table_test.rb b/activerecord/test/cases/associations/habtm_join_table_test.rb index bf3e04c3eb..745f169ad7 100644 --- a/activerecord/test/cases/associations/habtm_join_table_test.rb +++ b/activerecord/test/cases/associations/habtm_join_table_test.rb @@ -36,21 +36,9 @@ class HabtmJoinTableTest < ActiveRecord::TestCase uses_transaction :test_should_raise_exception_when_join_table_has_a_primary_key def test_should_raise_exception_when_join_table_has_a_primary_key if ActiveRecord::Base.connection.supports_primary_key? - assert_raise ActiveRecord::ConfigurationError do - jaime = MyReader.create(:name=>"Jaime") - jaime.my_books << MyBook.create(:name=>'Great Expectations') + assert_raise ActiveRecord::HasAndBelongsToManyAssociationWithPrimaryKeyError do + MyReader.has_and_belongs_to_many :my_books end end end - - uses_transaction :test_should_cache_result_of_primary_key_check - def test_should_cache_result_of_primary_key_check - if ActiveRecord::Base.connection.supports_primary_key? - ActiveRecord::Base.connection.stubs(:primary_key).with('my_books_my_readers').returns(false).once - weaz = MyReader.create(:name=>'Weaz') - - weaz.my_books << MyBook.create(:name=>'Great Expectations') - weaz.my_books << MyBook.create(:name=>'Greater Expectations') - end - end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 86d14c9c81..ce7eedbb54 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1179,4 +1179,3 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal firm.name, client.firm_name end end - diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 5f13b66d11..608d5a3608 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -137,6 +137,28 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert !posts(:welcome).reload.people(true).include?(people(:michael)) end + def test_replace_order_is_preserved + posts(:welcome).people.clear + posts(:welcome).people = [people(:david), people(:michael)] + assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id) + + # Test the inverse order in case the first success was a coincidence + posts(:welcome).people.clear + posts(:welcome).people = [people(:michael), people(:david)] + assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id) + end + + def test_replace_by_id_order_is_preserved + posts(:welcome).people.clear + posts(:welcome).person_ids = [people(:david).id, people(:michael).id] + assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id) + + # Test the inverse order in case the first success was a coincidence + posts(:welcome).people.clear + posts(:welcome).person_ids = [people(:michael).id, people(:david).id] + assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id) + end + def test_associate_with_create assert_queries(1) { posts(:thinking) } diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 289c89d1e2..d359ad48c5 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -327,10 +327,4 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert !account.new_record? assert_equal 500, account.credit_limit end - - def test_create!_respects_hash_condition - account = companies(:first_firm).create_account_limit_500_with_hash_conditions! - assert !account.new_record? - assert_equal 500, account.credit_limit - end end 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/associations_test.rb b/activerecord/test/cases/associations_test.rb index e429c1d157..9bc34bd750 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -64,6 +64,16 @@ class AssociationsTest < ActiveRecord::TestCase assert !firm.clients(true).empty?, "New firm should have reloaded client objects" assert_equal 1, firm.clients(true).size, "New firm should have reloaded clients count" end + + def test_force_reload_is_uncached + firm = Firm.create!("name" => "A New Firm, Inc") + client = Client.create!("name" => "TheClient.com", :firm => firm) + ActiveRecord::Base.cache do + firm.clients.each {} + assert_queries(0) { assert_not_nil firm.clients.each {} } + assert_queries(1) { assert_not_nil firm.clients(true).each {} } + end + end end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 9164701601..cf763d730a 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 @@ -757,14 +786,14 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase def test_should_automatically_validate_the_associated_model @pirate.ship.name = '' assert @pirate.invalid? - assert @pirate.errors[:ship_name].any? + assert @pirate.errors[:"ship.name"].any? end def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid @pirate.ship.name = nil @pirate.catchphrase = nil assert @pirate.invalid? - assert @pirate.errors[:ship_name].any? + assert @pirate.errors[:"ship.name"].any? assert @pirate.errors[:catchphrase].any? end @@ -857,7 +886,7 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase def test_should_automatically_validate_the_associated_model @ship.pirate.catchphrase = '' assert @ship.invalid? - assert @ship.errors[:pirate_catchphrase].any? + assert @ship.errors[:"pirate.catchphrase"].any? end def test_should_merge_errors_on_the_associated_model_onto_the_parent_even_if_it_is_not_valid @@ -865,7 +894,7 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase @ship.pirate.catchphrase = nil assert @ship.invalid? assert @ship.errors[:name].any? - assert @ship.errors[:pirate_catchphrase].any? + assert @ship.errors[:"pirate.catchphrase"].any? end def test_should_still_allow_to_bypass_validations_on_the_associated_model @@ -932,7 +961,7 @@ module AutosaveAssociationOnACollectionAssociationTests @pirate.send(@association_name).each { |child| child.name = '' } assert !@pirate.valid? - assert_equal ["can't be blank"], @pirate.errors["#{@association_name}_name"] + assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"] assert @pirate.errors[@association_name].empty? end @@ -940,8 +969,25 @@ module AutosaveAssociationOnACollectionAssociationTests @pirate.send(@association_name).build(:name => '') assert !@pirate.valid? - assert_equal ["can't be blank"], @pirate.errors["#{@association_name}_name"] + assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"] + assert @pirate.errors[@association_name].empty? + end + + def test_should_default_invalid_error_from_i18n + I18n.backend.store_translations(:en, :activerecord => { :errors => { :models => + { @association_name.to_s.singularize.to_sym => { :blank => "cannot be blank" } } + }}) + + @pirate.send(@association_name).build(:name => '') + + assert !@pirate.valid? + assert_equal ["cannot be blank"], @pirate.errors["#{@association_name}.name"] + assert_equal ["#{@association_name.to_s.titleize} name cannot be blank"], @pirate.errors.full_messages assert @pirate.errors[@association_name].empty? + ensure + I18n.backend.store_translations(:en, :activerecord => { :errors => { :models => + { @association_name.to_s.singularize.to_sym => nil } + }}) end def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid @@ -949,7 +995,7 @@ module AutosaveAssociationOnACollectionAssociationTests @pirate.catchphrase = nil assert !@pirate.valid? - assert_equal ["can't be blank"], @pirate.errors["#{@association_name}_name"] + assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"] assert @pirate.errors[:catchphrase].any? end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 5c2911eca1..730d9d8df7 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -201,7 +201,7 @@ class BasicsTest < ActiveRecord::TestCase topic = Topic.new(:title => "New Topic") assert topic.save! - reply = Reply.new + reply = WrongReply.new assert_raise(ActiveRecord::RecordInvalid) { reply.save! } end @@ -680,6 +680,16 @@ class BasicsTest < ActiveRecord::TestCase assert_equal -2, Topic.find(2).replies_count end + def test_reset_counters + assert_equal 1, Topic.find(1).replies_count + + Topic.increment_counter("replies_count", 1) + assert_equal 2, Topic.find(1).replies_count + + Topic.reset_counters(1, :replies) + assert_equal 1, Topic.find(1).replies_count + end + def test_update_counter category = categories(:general) assert_nil category.categorizations_count @@ -949,6 +959,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_update_attributes! + Reply.validates_presence_of(:title) reply = Reply.find(2) assert_equal "The Second Topic of the day", reply.title assert_equal "Have a nice day", reply.content @@ -964,6 +975,8 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "Have a nice day", reply.content assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") } + ensure + Reply.reset_callbacks(:validate) end def test_mass_assignment_should_raise_exception_if_accessible_and_protected_attribute_writers_are_both_used @@ -1815,7 +1828,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 @@ -1823,7 +1836,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)) @@ -1837,17 +1850,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)) @@ -1859,7 +1872,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 @@ -1867,7 +1880,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 @@ -1877,7 +1890,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 @@ -1892,8 +1905,14 @@ class BasicsTest < ActiveRecord::TestCase assert_equal Developer.find(:first, :order => 'id desc'), Developer.last end + def test_all + developers = Developer.all + assert_kind_of Array, developers + assert_equal Developer.find(:all), developers + end + def test_all_with_conditions - assert_equal Developer.find(:all, :order => 'id desc'), Developer.all.order('id desc').to_a + assert_equal Developer.find(:all, :order => 'id desc'), Developer.order('id desc').all end def test_find_ordered_last @@ -1917,7 +1936,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/batches_test.rb b/activerecord/test/cases/batches_test.rb index 5009a90846..e417d8a803 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -5,7 +5,7 @@ class EachTest < ActiveRecord::TestCase fixtures :posts def setup - @posts = Post.all(:order => "id asc") + @posts = Post.order("id asc") @total = Post.count end 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/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index f456d273fe..4961d12a44 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -301,7 +301,7 @@ class DirtyTest < ActiveRecord::TestCase def test_save_should_not_save_serialized_attribute_with_partial_updates_if_not_present with_partial_updates(Topic) do Topic.create!(:author_name => 'Bill', :content => {:a => "a"}) - topic = Topic.first(:select => 'id, author_name') + topic = Topic.select('id, author_name').first topic.update_attribute :author_name, 'John' topic = Topic.first assert_not_nil topic.content diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 3de07797d4..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 @@ -233,11 +233,11 @@ class FinderTest < ActiveRecord::TestCase end def test_first - assert_equal topics(:second).title, Topic.first(:conditions => "title = 'The Second Topic of the day'").title + assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title end def test_first_failing - assert_nil Topic.first(:conditions => "title = 'The Second Topic of the day!'") + assert_nil Topic.where("title = 'The Second Topic of the day!'").first end def test_unexisting_record_exception_handling @@ -291,7 +291,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_with_hash_conditions_on_joined_table - firms = Firm.all :joins => :account, :conditions => {:accounts => { :credit_limit => 50 }} + firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 }) assert_equal 1, firms.size assert_equal companies(:first_firm), firms.first end @@ -571,21 +571,6 @@ class FinderTest < ActiveRecord::TestCase assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1])) end - def test_dynamic_finders_should_go_through_the_find_class_method - Topic.expects(:find).with(:first, :conditions => { :title => 'The First Topic!' }) - Topic.find_by_title("The First Topic!") - - Topic.expects(:find).with(:last, :conditions => { :title => 'The Last Topic!' }) - Topic.find_last_by_title("The Last Topic!") - - Topic.expects(:find).with(:all, :conditions => { :title => 'A Topic.' }) - Topic.find_all_by_title("A Topic.") - - Topic.expects(:find).with(:first, :conditions => { :title => 'Does not exist yet for sure!' }).times(2) - Topic.find_or_initialize_by_title('Does not exist yet for sure!') - Topic.find_or_create_by_title('Does not exist yet for sure!') - end - def test_find_by_one_attribute assert_equal topics(:first), Topic.find_by_title("The First Topic") assert_nil Topic.find_by_title("The First Topic!") @@ -596,21 +581,6 @@ class FinderTest < ActiveRecord::TestCase assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") } end - def test_find_by_one_attribute_caches_dynamic_finder - # ensure this test can run independently of order - class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_by_title' } - assert !Topic.public_methods.any? { |m| m.to_s == 'find_by_title' } - t = Topic.find_by_title("The First Topic") - assert Topic.public_methods.any? { |m| m.to_s == 'find_by_title' } - end - - def test_dynamic_finder_returns_same_results_after_caching - # ensure this test can run independently of order - class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_method_defined?(:find_by_title) - t = Topic.find_by_title("The First Topic") - assert_equal t, Topic.find_by_title("The First Topic") # find_by_title has been cached - end - def test_find_by_one_attribute_with_order_option assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id') assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC') @@ -654,14 +624,6 @@ class FinderTest < ActiveRecord::TestCase assert_equal customers(:david), found_customer end - def test_dynamic_finder_on_one_attribute_with_conditions_caches_method - # ensure this test can run independently of order - class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' } - assert !Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' } - a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) - assert Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' } - end - def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching # ensure this test can run independently of order class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' } @@ -694,14 +656,6 @@ class FinderTest < ActiveRecord::TestCase assert_nil Topic.find_last_by_title("A title with no matches") end - def test_find_last_by_one_attribute_caches_dynamic_finder - # ensure this test can run independently of order - class << Topic; self; end.send(:remove_method, :find_last_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } - assert !Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } - t = Topic.find_last_by_title(Topic.last.title) - assert Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } - end - def test_find_last_by_invalid_method_syntax assert_raise(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") } assert_raise(NoMethodError) { Topic.find_last_by_title?("The First Topic") } @@ -926,13 +880,6 @@ class FinderTest < ActiveRecord::TestCase assert !c.new_record? end - def test_dynamic_find_or_initialize_from_one_attribute_caches_method - class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' } - assert !Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' } - sig38 = Company.find_or_initialize_by_name("38signals") - assert Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' } - end - def test_find_or_initialize_from_two_attributes another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John") assert_equal "Another topic", another.title @@ -1075,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 25613da912..479970b2fa 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -1,11 +1,9 @@ -root = File.expand_path('../../../..', __FILE__) begin - require "#{root}/vendor/gems/environment" + require File.expand_path('../../../../vendor/gems/environment', __FILE__) rescue LoadError - $:.unshift("#{root}/activesupport/lib") end -lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib") +lib = File.expand_path('../../../lib', __FILE__) $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) require 'config' @@ -49,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) @@ -64,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 f946e8699e..dfaecf35cf 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -38,24 +38,6 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_raise(ActiveRecord::StaleObjectError) { p2.save! } end - def test_lock_destroy - p1 = Person.find(1) - p2 = Person.find(1) - assert_equal 0, p1.lock_version - assert_equal 0, p2.lock_version - - p1.first_name = 'stu' - p1.save! - assert_equal 1, p1.lock_version - assert_equal 0, p2.lock_version - - assert_raises(ActiveRecord::StaleObjectError) { p2.destroy } - - assert p1.destroy - assert_equal true, p1.frozen? - assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) } - end - def test_lock_repeating p1 = Person.find(1) p2 = Person.find(1) @@ -243,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/migration_test.rb b/activerecord/test/cases/migration_test.rb index 6d3f938799..0ef34e440a 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -527,6 +527,53 @@ if ActiveRecord::Base.connection.supports_migrations? assert !Person.column_methods_hash.include?(:last_name) end + if current_adapter?(:MysqlAdapter) + def testing_table_for_positioning + Person.connection.create_table :testings, :id => false do |t| + t.column :first, :integer + t.column :second, :integer + t.column :third, :integer + end + + yield Person.connection + ensure + Person.connection.drop_table :testings rescue nil + end + protected :testing_table_for_positioning + + def test_column_positioning + testing_table_for_positioning do |conn| + assert_equal %w(first second third), conn.columns(:testings).map {|c| c.name } + end + end + + def test_add_column_with_positioning + testing_table_for_positioning do |conn| + conn.add_column :testings, :new_col, :integer + assert_equal %w(first second third new_col), conn.columns(:testings).map {|c| c.name } + end + testing_table_for_positioning do |conn| + conn.add_column :testings, :new_col, :integer, :first => true + assert_equal %w(new_col first second third), conn.columns(:testings).map {|c| c.name } + end + testing_table_for_positioning do |conn| + conn.add_column :testings, :new_col, :integer, :after => :first + assert_equal %w(first new_col second third), conn.columns(:testings).map {|c| c.name } + end + end + + def test_change_column_with_positioning + testing_table_for_positioning do |conn| + conn.change_column :testings, :second, :integer, :first => true + assert_equal %w(second first third), conn.columns(:testings).map {|c| c.name } + end + testing_table_for_positioning do |conn| + conn.change_column :testings, :second, :integer, :after => :third + assert_equal %w(first third second), conn.columns(:testings).map {|c| c.name } + end + end + end + def test_add_rename Person.delete_all diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb index 7c3e0f2ca6..6155bfd50a 100644 --- a/activerecord/test/cases/multiple_db_test.rb +++ b/activerecord/test/cases/multiple_db_test.rb @@ -1,5 +1,6 @@ require "cases/helper" require 'models/entrant' +require 'models/bird' # So we can test whether Course.connection survives a reload. require_dependency 'models/course' @@ -82,4 +83,9 @@ class MultipleDbTest < ActiveRecord::TestCase assert_equal "Ruby Development", Course.find(1).name assert_equal "Ruby Developer", Entrant.find(1).name end + + def test_arel_table_engines + assert_not_equal Entrant.active_relation_engine, Course.active_relation_engine + assert_equal Entrant.active_relation_engine, Bird.active_relation_engine + end end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 13427daf53..5d9232bc52 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -345,8 +345,8 @@ class NamedScopeTest < ActiveRecord::TestCase def test_chaining_should_use_latest_conditions_when_searching # Normal hash conditions - assert_equal Topic.all(:conditions => {:approved => true}).to_a, Topic.rejected.approved.all.to_a - assert_equal Topic.all(:conditions => {:approved => false}).to_a, Topic.approved.rejected.all.to_a + assert_equal Topic.where(:approved => true).to_a, Topic.rejected.approved.all.to_a + assert_equal Topic.where(:approved => false).to_a, Topic.approved.rejected.all.to_a # Nested hash conditions with same keys assert_equal [posts(:sti_comments)], Post.with_special_comments.with_very_special_comments.all.to_a diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 53fd168e1b..8891282915 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 @@ -541,7 +592,7 @@ module NestedAttributesOnACollectionAssociationTests assert_no_difference ['Man.count', 'Interest.count'] do man = Man.create(:name => 'John', :interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}]) - assert !man.errors[:interests_man].empty? + assert !man.errors[:"interests.man"].empty? end end # restore :inverse_of 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 1a2c8030fb..f895f8b8d2 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1,4 +1,6 @@ require "cases/helper" +require 'models/tag' +require 'models/tagging' require 'models/post' require 'models/topic' require 'models/comment' @@ -8,52 +10,115 @@ require 'models/comment' require 'models/entrant' require 'models/developer' require 'models/company' +require 'models/bird' class RelationTest < ActiveRecord::TestCase - fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments + fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, + :taggings + + def test_scoped + topics = Topic.scoped + assert_kind_of ActiveRecord::Relation, topics + assert_equal 4, topics.size + end + + def test_scoped_all + topics = Topic.scoped.all + assert_kind_of Array, topics + assert_no_queries { assert_equal 4, topics.size } + end + + def test_loaded_all + topics = Topic.scoped + + assert_queries(1) do + 2.times { assert_equal 4, topics.all.size } + end + + assert topics.loaded? + end + + def test_scoped_first + topics = Topic.scoped.order('id ASC') + + assert_queries(1) do + 2.times { assert_equal "The First Topic", topics.first.title } + end + + assert ! topics.loaded? + end + + def test_loaded_first + topics = Topic.scoped.order('id ASC') + + assert_queries(1) do + topics.all # force load + 2.times { assert_equal "The First Topic", topics.first.title } + end + + assert topics.loaded? + end + + def test_reload + topics = Topic.scoped + + assert_queries(1) do + 2.times { topics.to_a } + end + + assert topics.loaded? + + topics.reload + assert ! topics.loaded? + + assert_queries(1) { topics.to_a } + end def test_finding_with_conditions - assert_equal Author.find(:all, :conditions => "name = 'David'"), Author.all.conditions("name = 'David'").to_a + assert_equal ["David"], Author.where(:name => 'David').map(&:name) + assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name) + assert_equal ['Mary'], Author.where("name = ?", 'Mary').map(&:name) end def test_finding_with_order - topics = Topic.all.order('id') - assert_equal 4, topics.size + topics = Topic.order('id') + assert_equal 4, topics.to_a.size assert_equal topics(:first).title, topics.first.title end def test_finding_with_order_and_take - entrants = Entrant.all.order("id ASC").limit(2).to_a + entrants = Entrant.order("id ASC").limit(2).to_a - assert_equal(2, entrants.size) - assert_equal(entrants(:first).name, entrants.first.name) + assert_equal 2, entrants.size + assert_equal entrants(:first).name, entrants.first.name end def test_finding_with_order_limit_and_offset - entrants = Entrant.all.order("id ASC").limit(2).offset(1) + entrants = Entrant.order("id ASC").limit(2).offset(1) - assert_equal(2, entrants.size) - assert_equal(entrants(:second).name, entrants.first.name) + assert_equal 2, entrants.to_a.size + assert_equal entrants(:second).name, entrants.first.name - entrants = Entrant.all.order("id ASC").limit(2).offset(2) - assert_equal(1, entrants.size) - assert_equal(entrants(:third).name, entrants.first.name) + entrants = Entrant.order("id ASC").limit(2).offset(2) + assert_equal 1, entrants.to_a.size + assert_equal entrants(:third).name, entrants.first.name end def test_finding_with_group - developers = Developer.all.group("salary").select("salary").to_a + developers = Developer.group("salary").select("salary").to_a assert_equal 4, developers.size assert_equal 4, developers.map(&:salary).uniq.size end def test_finding_with_hash_conditions_on_joined_table - firms = DependentFirm.all.joins(:account).conditions({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a + firms = DependentFirm.joins(:account).where({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a assert_equal 1, firms.size assert_equal companies(:rails_core), firms.first end def test_find_all_with_join - developers_on_project_one = Developer.all.joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').conditions('project_id=1').to_a + developers_on_project_one = Developer.joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id'). + where('project_id=1').to_a assert_equal 3, developers_on_project_one.length developer_names = developers_on_project_one.map { |d| d.name } @@ -62,11 +127,11 @@ class RelationTest < ActiveRecord::TestCase end def test_find_on_hash_conditions - assert_equal Topic.find(:all, :conditions => {:approved => false}), Topic.all.conditions({ :approved => false }).to_a + assert_equal Topic.find(:all, :conditions => {:approved => false}), Topic.where({ :approved => false }).to_a end def test_joins_with_string_array - person_with_reader_and_post = Post.all.joins([ + person_with_reader_and_post = Post.joins([ "INNER JOIN categorizations ON categorizations.post_id = posts.id", "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'" ] @@ -74,22 +139,38 @@ class RelationTest < ActiveRecord::TestCase assert_equal 1, person_with_reader_and_post.size end - def test_relation_responds_to_delegated_methods - relation = Topic.all + def test_scoped_responds_to_delegated_methods + 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 def test_find_with_readonly_option - Developer.all.each { |d| assert !d.readonly? } - Developer.all.readonly.each { |d| assert d.readonly? } - Developer.all(:readonly => true).each { |d| assert d.readonly? } + Developer.scoped.each { |d| assert !d.readonly? } + Developer.scoped.readonly.each { |d| assert d.readonly? } end def test_eager_association_loading_of_stis_with_multiple_references - authors = Author.all(:include => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4').to_a + authors = Author.eager_load(:posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } }). + order('comments.body, very_special_comments_posts.body').where('posts.id = 4').to_a + assert_equal [authors(:david)], authors assert_no_queries do authors.first.posts.first.special_comments.first.post.special_comments @@ -97,54 +178,382 @@ class RelationTest < ActiveRecord::TestCase end end - def test_find_with_included_associations + def test_find_with_preloaded_associations assert_queries(2) do - posts = Post.find(:all, :include => :comments) - posts.first.comments.first + posts = Post.preload(:comments) + assert posts.first.comments.first end + assert_queries(2) do - posts = Post.all(:include => :comments).to_a - posts.first.comments.first + posts = Post.preload(:comments).to_a + assert posts.first.comments.first end + assert_queries(2) do - posts = Post.find(:all, :include => :author) - posts.first.author + posts = Post.preload(:author) + assert posts.first.author end + assert_queries(2) do - posts = Post.all(:include => :author).to_a - posts.first.author + posts = Post.preload(:author).to_a + assert posts.first.author + end + + assert_queries(3) do + posts = Post.preload(:author, :comments).to_a + assert posts.first.author + assert posts.first.comments.first end end - def test_default_scope_with_conditions_string - assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.all.to_a.map(&:id).sort + def test_find_with_included_associations + assert_queries(2) do + posts = Post.includes(:comments) + assert posts.first.comments.first + end + + assert_queries(2) do + posts = Post.scoped.includes(:comments) + assert posts.first.comments.first + end + + assert_queries(2) do + posts = Post.includes(:author) + assert posts.first.author + end + + assert_queries(3) do + posts = Post.includes(:author, :comments).to_a + assert posts.first.author + assert posts.first.comments.first + end + end + + def test_default_scope_with_conditions_string + assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.map(&:id).sort assert_equal nil, DeveloperCalledDavid.create!.name end def test_default_scope_with_conditions_hash - assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort + assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.scoped.map(&:id).sort assert_equal 'Jamis', DeveloperCalledJamis.create!.name end - def test_loading_with_one_association - posts = Post.all(:include => :comments) + def test_default_scoping_finder_methods + developers = DeveloperCalledDavid.order('id').map(&:id).sort + assert_equal Developer.find_all_by_name('David').map(&:id).sort, developers + end + + def test_loading_with_one_association + posts = Post.preload(:comments) post = posts.find { |p| p.id == 1 } assert_equal 2, post.comments.size assert post.comments.include?(comments(:greetings)) - post = Post.find(:first, :include => :comments, :conditions => "posts.title = 'Welcome to the weblog'") + post = Post.where("posts.title = 'Welcome to the weblog'").preload(:comments).first assert_equal 2, post.comments.size assert post.comments.include?(comments(:greetings)) - posts = Post.all(:include => :last_comment) + posts = Post.preload(:last_comment) post = posts.find { |p| p.id == 1 } assert_equal Post.find(1).last_comment, post.last_comment end def test_loading_with_one_association_with_non_preload - posts = Post.all(:include => :last_comment, :order => 'comments.id DESC') + posts = Post.eager_load(:last_comment).order('comments.id DESC') post = posts.find { |p| p.id == 1 } assert_equal Post.find(1).last_comment, post.last_comment end -end + def test_dynamic_find_by_attributes + david = authors(:david) + author = Author.preload(:taggings).find_by_id(david.id) + expected_taggings = taggings(:welcome_general, :thinking_general) + + assert_no_queries do + assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id } + end + + authors = Author.scoped + assert_equal david, authors.find_by_id_and_name(david.id, david.name) + assert_equal david, authors.find_by_id_and_name!(david.id, david.name) + end + + def test_dynamic_find_by_attributes_bang + 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!(20, 'invalid') } + end + + def test_dynamic_find_all_by_attributes + authors = Author.scoped + + davids = authors.find_all_by_name('David') + assert_kind_of Array, davids + assert_equal [authors(:david)], davids + end + + def test_dynamic_find_or_initialize_by_attributes + authors = Author.scoped + + lifo = authors.find_or_initialize_by_name('Lifo') + assert_equal "Lifo", lifo.name + assert lifo.new_record? + + assert_equal authors(:david), authors.find_or_initialize_by_name(:name => 'David') + end + + def test_dynamic_find_or_create_by_attributes + authors = Author.scoped + + lifo = authors.find_or_create_by_name('Lifo') + assert_equal "Lifo", lifo.name + assert ! lifo.new_record? + + assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David') + end + + def test_find_id + authors = Author.scoped + + david = authors.find(authors(:david).id) + assert_equal 'David', david.name + + assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('42') } + end + + def test_find_ids + authors = Author.order('id ASC') + + results = authors.find(authors(:david).id, authors(:mary).id) + assert_kind_of Array, results + assert_equal 2, results.size + assert_equal 'David', results[0].name + 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, '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_locks + devs = Developer.lock.where("salary >= 80000").order("id DESC") & Developer.limit(2) + assert devs.locked.present? + 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').group('id').order('id').count.values.uniq + 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 + + def test_any + posts = Post.scoped + + assert_queries(3) do + assert posts.any? # Uses COUNT() + assert ! posts.where(:id => nil).any? + + assert posts.any? {|p| p.id > 0 } + assert ! posts.any? {|p| p.id <= 0 } + end + + assert posts.loaded? + end + + def test_many + posts = Post.scoped + + assert_queries(2) do + assert posts.many? # Uses COUNT() + assert posts.many? {|p| p.id > 0 } + assert ! posts.many? {|p| p.id < 2 } + end + + assert posts.loaded? + end + + def test_many_with_limits + posts = Post.scoped + + assert posts.many? + assert ! posts.limit(1).many? + end + + def test_build + posts = Post.scoped + + post = posts.new + assert_kind_of Post, post + end + + def test_scoped_build + posts = Post.where(:title => 'You told a lie') + + post = posts.new + assert_kind_of Post, post + assert_equal 'You told a lie', post.title + end + + def test_create + birds = Bird.scoped + + sparrow = birds.create + assert_kind_of Bird, sparrow + assert sparrow.new_record? + + hen = birds.where(:name => 'hen').create + assert ! hen.new_record? + assert_equal 'hen', hen.name + end + + def test_create_bang + birds = Bird.scoped + + assert_raises(ActiveRecord::RecordInvalid) { birds.create! } + + hen = birds.where(:name => 'hen').create! + assert_kind_of Bird, hen + assert ! hen.new_record? + assert_equal 'hen', hen.name + end + + def test_except + relation = Post.where(:author_id => 1).order('id ASC').limit(1) + assert_equal [posts(:welcome)], relation.all + + author_posts = relation.except(:order, :limit) + assert_equal Post.where(:author_id => 1).all, author_posts.all + + all_posts = relation.except(:where, :order, :limit) + assert_equal Post.all, all_posts.all + end + +end diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb index 278a7a6a06..5ed997356b 100644 --- a/activerecord/test/cases/validations/association_validation_test.rb +++ b/activerecord/test/cases/validations/association_validation_test.rb @@ -10,7 +10,7 @@ require 'models/interest' class AssociationValidationTest < ActiveRecord::TestCase fixtures :topics, :owners - repair_validations(Topic) + repair_validations(Topic, Reply) def test_validates_size_of_association repair_validations(Owner) do @@ -40,7 +40,8 @@ class AssociationValidationTest < ActiveRecord::TestCase end def test_validates_associated_many - Topic.validates_associated( :replies ) + Topic.validates_associated(:replies) + Reply.validates_presence_of(:content) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") t.replies << [r = Reply.new("title" => "A reply"), r2 = Reply.new("title" => "Another reply", "content" => "non-empty"), r3 = Reply.new("title" => "Yet another reply"), r4 = Reply.new("title" => "The last reply", "content" => "non-empty")] assert !t.valid? diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index 532de67d99..f017f24048 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -3,8 +3,9 @@ require 'models/topic' require 'models/reply' class I18nValidationTest < ActiveRecord::TestCase + repair_validations(Topic, Reply) def setup - Topic.reset_callbacks(:validate) + Reply.validates_presence_of(:title) @topic = Topic.new @old_load_path, @old_backend = I18n.load_path, I18n.backend I18n.load_path.clear @@ -13,7 +14,6 @@ class I18nValidationTest < ActiveRecord::TestCase end def teardown - Topic.reset_callbacks(:validate) I18n.load_path.replace @old_load_path I18n.backend = @old_backend end diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index 17ba4e2f8a..8f84841fe6 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -5,7 +5,6 @@ require 'models/reply' require 'models/warehouse_thing' require 'models/guid' require 'models/event' -require 'models/developer' # The following methods in Topic are used in test_conditional_validation_* class Topic @@ -213,7 +212,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") @@ -276,14 +275,4 @@ class UniquenessValidationTest < ActiveRecord::TestCase assert w6.errors[:city].any?, "Should have errors for city" assert_equal ["has already been taken"], w6.errors[:city], "Should have uniqueness message for city" end - - def test_validates_uniqueness_of_with_custom_message_using_quotes - repair_validations(Developer) do - Developer.validates_uniqueness_of :name, :message=> "This string contains 'single' and \"double\" quotes" - d = Developer.new - d.name = "David" - assert !d.valid? - assert_equal ["This string contains 'single' and \"double\" quotes"], d.errors[:name] - end - end end diff --git a/activerecord/test/cases/validations_repair_helper.rb b/activerecord/test/cases/validations_repair_helper.rb new file mode 100644 index 0000000000..11912ca1cc --- /dev/null +++ b/activerecord/test/cases/validations_repair_helper.rb @@ -0,0 +1,23 @@ +module ActiveRecord + module ValidationsRepairHelper + extend ActiveSupport::Concern + + module ClassMethods + def repair_validations(*model_classes) + teardown do + model_classes.each do |k| + k.reset_callbacks(:validate) + end + end + end + end + + def repair_validations(*model_classes) + yield + ensure + model_classes.each do |k| + k.reset_callbacks(:validate) + end + end + end +end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 130231c622..3a1d5ae212 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -42,7 +42,7 @@ class ValidationsTest < ActiveRecord::TestCase repair_validations(Topic) def test_error_on_create - r = Reply.new + r = WrongReply.new r.title = "Wrong Create" assert !r.valid? assert r.errors[:title].any?, "A reply with a bad title should mark that attribute as invalid" @@ -50,7 +50,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_error_on_update - r = Reply.new + r = WrongReply.new r.title = "Bad" r.content = "Good" assert r.save, "First save should be successful" @@ -63,11 +63,11 @@ class ValidationsTest < ActiveRecord::TestCase end def test_invalid_record_exception - assert_raise(ActiveRecord::RecordInvalid) { Reply.create! } - assert_raise(ActiveRecord::RecordInvalid) { Reply.new.save! } + assert_raise(ActiveRecord::RecordInvalid) { WrongReply.create! } + assert_raise(ActiveRecord::RecordInvalid) { WrongReply.new.save! } begin - r = Reply.new + r = WrongReply.new r.save! flunk rescue ActiveRecord::RecordInvalid => invalid @@ -77,13 +77,13 @@ class ValidationsTest < ActiveRecord::TestCase def test_exception_on_create_bang_many assert_raise(ActiveRecord::RecordInvalid) do - Reply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }]) + WrongReply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }]) end end def test_exception_on_create_bang_with_block assert_raise(ActiveRecord::RecordInvalid) do - Reply.create!({ "title" => "OK" }) do |r| + WrongReply.create!({ "title" => "OK" }) do |r| r.content = nil end end @@ -91,21 +91,21 @@ class ValidationsTest < ActiveRecord::TestCase def test_exception_on_create_bang_many_with_block assert_raise(ActiveRecord::RecordInvalid) do - Reply.create!([{ "title" => "OK" }, { "title" => "Wrong Create" }]) do |r| + WrongReply.create!([{ "title" => "OK" }, { "title" => "Wrong Create" }]) do |r| r.content = nil end end end def test_scoped_create_without_attributes - Reply.with_scope(:create => {}) do - assert_raise(ActiveRecord::RecordInvalid) { Reply.create! } + WrongReply.send(:with_scope, :create => {}) do + assert_raise(ActiveRecord::RecordInvalid) { WrongReply.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 @@ -122,15 +122,15 @@ class ValidationsTest < ActiveRecord::TestCase end def test_create_without_validation - reply = Reply.new + reply = WrongReply.new assert !reply.save assert reply.save(false) end def test_create_without_validation_bang - count = Reply.count - assert_nothing_raised { Reply.new.save_without_validation! } - assert count+1, Reply.count + count = WrongReply.count + assert_nothing_raised { WrongReply.new.save_without_validation! } + assert count+1, WrongReply.count end def test_validates_acceptance_of_with_non_existant_table diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb new file mode 100644 index 0000000000..f221def6b6 --- /dev/null +++ b/activerecord/test/cases/yaml_serialization_test.rb @@ -0,0 +1,11 @@ +require "cases/helper" +require 'models/topic' + +class YamlSerializationTest < ActiveRecord::TestCase + def test_to_yaml_with_time_with_zone_should_not_raise_exception + Time.zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"] + ActiveRecord::Base.time_zone_aware_attributes = true + topic = Topic.new(:written_on => DateTime.now) + assert_nothing_raised { topic.to_yaml } + end +end diff --git a/activerecord/test/fixtures/edges.yml b/activerecord/test/fixtures/edges.yml index c16c70dd2f..b804f7b6a6 100644 --- a/activerecord/test/fixtures/edges.yml +++ b/activerecord/test/fixtures/edges.yml @@ -1,6 +1,5 @@ <% (1..4).each do |id| %> edge_<%= id %>: - id: <%= id %> source_id: <%= id %> sink_id: <%= id + 1 %> -<% end %>
\ No newline at end of file +<% end %> diff --git a/activerecord/test/fixtures/faces.yml b/activerecord/test/fixtures/faces.yml index 1dd2907cf7..c8e4a34484 100644 --- a/activerecord/test/fixtures/faces.yml +++ b/activerecord/test/fixtures/faces.yml @@ -5,3 +5,7 @@ trusting: weather_beaten: description: weather beaten man: steve + +confused: + description: confused + polymorphic_man: gordon (Man) diff --git a/activerecord/test/fixtures/interests.yml b/activerecord/test/fixtures/interests.yml index ec71890ab6..9200a19d5a 100644 --- a/activerecord/test/fixtures/interests.yml +++ b/activerecord/test/fixtures/interests.yml @@ -23,7 +23,11 @@ woodsmanship: zine: going_out man: steve -survial: +survival: topic: Survival zine: going_out man: steve + +llama_wrangling: + topic: Llama Wrangling + polymorphic_man: gordon (Man) diff --git a/activerecord/test/models/face.rb b/activerecord/test/models/face.rb index 1540dbf741..edb75d333f 100644 --- a/activerecord/test/models/face.rb +++ b/activerecord/test/models/face.rb @@ -1,5 +1,7 @@ class Face < ActiveRecord::Base belongs_to :man, :inverse_of => :face - # This is a "broken" inverse_of for the purposes of testing + belongs_to :polymorphic_man, :polymorphic => true, :inverse_of => :polymorphic_face + # These is a "broken" inverse_of for the purposes of testing belongs_to :horrible_man, :class_name => 'Man', :inverse_of => :horrible_face + belongs_to :horrible_polymorphic_man, :polymorphic => true, :inverse_of => :horrible_polymorphic_face end diff --git a/activerecord/test/models/interest.rb b/activerecord/test/models/interest.rb index d8291d00cc..d5d9226204 100644 --- a/activerecord/test/models/interest.rb +++ b/activerecord/test/models/interest.rb @@ -1,4 +1,5 @@ class Interest < ActiveRecord::Base belongs_to :man, :inverse_of => :interests + belongs_to :polymorphic_man, :polymorphic => true, :inverse_of => :polymorphic_interests belongs_to :zine, :inverse_of => :interests end diff --git a/activerecord/test/models/man.rb b/activerecord/test/models/man.rb index f40bc9d0fc..4bff92dc98 100644 --- a/activerecord/test/models/man.rb +++ b/activerecord/test/models/man.rb @@ -1,6 +1,8 @@ class Man < ActiveRecord::Base has_one :face, :inverse_of => :man + has_one :polymorphic_face, :class_name => 'Face', :as => :polymorphic_man, :inverse_of => :polymorphic_man has_many :interests, :inverse_of => :man + has_many :polymorphic_interests, :class_name => 'Interest', :as => :polymorphic_man, :inverse_of => :polymorphic_man # These are "broken" inverse_of associations for the purposes of testing has_one :dirty_face, :class_name => 'Face', :inverse_of => :dirty_man has_many :secret_interests, :class_name => 'Interest', :inverse_of => :secret_man diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index f2c05dd48f..88c1634717 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -19,6 +19,7 @@ class Pirate < ActiveRecord::Base # These both have :autosave enabled because accepts_nested_attributes_for is used on them. has_one :ship + has_one :update_only_ship, :class_name => 'Ship' has_one :non_validated_ship, :class_name => 'Ship' has_many :birds has_many :birds_with_method_callbacks, :class_name => "Bird", @@ -35,6 +36,7 @@ class Pirate < ActiveRecord::Base accepts_nested_attributes_for :parrots, :birds, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } + accepts_nested_attributes_for :update_only_ship, :update_only => true accepts_nested_attributes_for :parrots_with_method_callbacks, :parrots_with_proc_callbacks, :birds_with_method_callbacks, :birds_with_proc_callbacks, :allow_destroy => true accepts_nested_attributes_for :birds_with_reject_all_blank, :reject_if => :all_blank diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb index ba5a1d1d01..f1ba45b528 100644 --- a/activerecord/test/models/reply.rb +++ b/activerecord/test/models/reply.rb @@ -7,11 +7,13 @@ class Reply < Topic belongs_to :topic_with_primary_key, :class_name => "Topic", :primary_key => "title", :foreign_key => "parent_title", :counter_cache => "replies_count" has_many :replies, :class_name => "SillyReply", :dependent => :destroy, :foreign_key => "parent_id" + attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read, :parent_title +end + +class WrongReply < Reply validate :errors_on_empty_content validate :title_is_wrong_create, :on => :create - attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read, :parent_title - validate :check_empty_title validate :check_content_mismatch, :on => :create validate :check_wrong_update, :on => :update diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb index 06759d64b8..a96e38ab41 100644 --- a/activerecord/test/models/ship.rb +++ b/activerecord/test/models/ship.rb @@ -2,9 +2,11 @@ class Ship < ActiveRecord::Base self.record_timestamps = false belongs_to :pirate + belongs_to :update_only_pirate, :class_name => 'Pirate' has_many :parts, :class_name => 'ShipPart', :autosave => true accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } + accepts_nested_attributes_for :update_only_pirate, :update_only => true validates_presence_of :name end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 15e5e12d03..1ec36e7832 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -160,7 +160,7 @@ ActiveRecord::Schema.define do t.integer :access_level, :default => 1 end - create_table :edges, :force => true do |t| + create_table :edges, :force => true, :id => false do |t| t.column :source_id, :integer, :null => false t.column :sink_id, :integer, :null => false end @@ -520,11 +520,15 @@ ActiveRecord::Schema.define do create_table :faces, :force => true do |t| t.string :description t.integer :man_id + t.integer :polymorphic_man_id + t.string :polymorphic_man_type end create_table :interests, :force => true do |t| t.string :topic t.integer :man_id + t.integer :polymorphic_man_id + t.string :polymorphic_man_type t.integer :zine_id end |