activerecord 2.0.5 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +168 -6
- data/README +27 -22
- data/RUNNING_UNIT_TESTS +7 -4
- data/Rakefile +22 -25
- data/lib/active_record.rb +8 -2
- data/lib/active_record/aggregations.rb +21 -12
- data/lib/active_record/association_preload.rb +277 -0
- data/lib/active_record/associations.rb +481 -295
- data/lib/active_record/associations/association_collection.rb +162 -37
- data/lib/active_record/associations/association_proxy.rb +71 -7
- data/lib/active_record/associations/belongs_to_association.rb +5 -3
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +5 -6
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -64
- data/lib/active_record/associations/has_many_association.rb +8 -73
- data/lib/active_record/associations/has_many_through_association.rb +68 -117
- data/lib/active_record/associations/has_one_association.rb +7 -5
- data/lib/active_record/associations/has_one_through_association.rb +28 -0
- data/lib/active_record/attribute_methods.rb +69 -19
- data/lib/active_record/base.rb +496 -275
- data/lib/active_record/calculations.rb +28 -21
- data/lib/active_record/callbacks.rb +9 -38
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +3 -2
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +232 -45
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +141 -27
- data/lib/active_record/connection_adapters/abstract_adapter.rb +9 -13
- data/lib/active_record/connection_adapters/mysql_adapter.rb +57 -24
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +143 -42
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +18 -10
- data/lib/active_record/dirty.rb +158 -0
- data/lib/active_record/fixtures.rb +121 -156
- data/lib/active_record/locking/optimistic.rb +14 -11
- data/lib/active_record/locking/pessimistic.rb +2 -2
- data/lib/active_record/migration.rb +157 -77
- data/lib/active_record/named_scope.rb +163 -0
- data/lib/active_record/observer.rb +19 -5
- data/lib/active_record/reflection.rb +34 -14
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +4 -4
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/serializers/json_serializer.rb +37 -28
- data/lib/active_record/serializers/xml_serializer.rb +52 -29
- data/lib/active_record/test_case.rb +36 -0
- data/lib/active_record/timestamp.rb +4 -4
- data/lib/active_record/transactions.rb +3 -3
- data/lib/active_record/validations.rb +182 -248
- data/lib/active_record/version.rb +2 -2
- data/test/{fixtures → assets}/example.log +0 -0
- data/test/{fixtures → assets}/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +24 -0
- data/test/cases/active_schema_test_mysql.rb +95 -0
- data/test/cases/active_schema_test_postgresql.rb +24 -0
- data/test/{adapter_test.rb → cases/adapter_test.rb} +15 -14
- data/test/{adapter_test_sqlserver.rb → cases/adapter_test_sqlserver.rb} +95 -95
- data/test/{aggregations_test.rb → cases/aggregations_test.rb} +20 -20
- data/test/{ar_schema_test.rb → cases/ar_schema_test.rb} +6 -6
- data/test/cases/associations/belongs_to_associations_test.rb +412 -0
- data/test/{associations → cases/associations}/callbacks_test.rb +24 -10
- data/test/{associations → cases/associations}/cascaded_eager_loading_test.rb +18 -17
- data/test/cases/associations/eager_load_nested_include_test.rb +83 -0
- data/test/{associations → cases/associations}/eager_singularization_test.rb +5 -5
- data/test/{associations → cases/associations}/eager_test.rb +216 -51
- data/test/{associations → cases/associations}/extension_test.rb +8 -8
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +684 -0
- data/test/cases/associations/has_many_associations_test.rb +932 -0
- data/test/cases/associations/has_many_through_associations_test.rb +190 -0
- data/test/cases/associations/has_one_associations_test.rb +323 -0
- data/test/cases/associations/has_one_through_associations_test.rb +74 -0
- data/test/{associations → cases/associations}/inner_join_association_test.rb +20 -20
- data/test/{associations → cases/associations}/join_model_test.rb +175 -35
- data/test/cases/associations_test.rb +262 -0
- data/test/{attribute_methods_test.rb → cases/attribute_methods_test.rb} +103 -11
- data/test/{base_test.rb → cases/base_test.rb} +338 -191
- data/test/{binary_test.rb → cases/binary_test.rb} +6 -4
- data/test/{calculations_test.rb → cases/calculations_test.rb} +35 -23
- data/test/{callbacks_test.rb → cases/callbacks_test.rb} +7 -7
- data/test/{class_inheritable_attributes_test.rb → cases/class_inheritable_attributes_test.rb} +3 -3
- data/test/{column_alias_test.rb → cases/column_alias_test.rb} +3 -3
- data/test/{connection_test_firebird.rb → cases/connection_test_firebird.rb} +2 -2
- data/test/{connection_test_mysql.rb → cases/connection_test_mysql.rb} +2 -2
- data/test/{copy_table_test_sqlite.rb → cases/copy_table_test_sqlite.rb} +13 -13
- data/test/{datatype_test_postgresql.rb → cases/datatype_test_postgresql.rb} +8 -8
- data/test/{date_time_test.rb → cases/date_time_test.rb} +5 -5
- data/test/{default_test_firebird.rb → cases/default_test_firebird.rb} +3 -3
- data/test/{defaults_test.rb → cases/defaults_test.rb} +8 -6
- data/test/{deprecated_finder_test.rb → cases/deprecated_finder_test.rb} +3 -3
- data/test/cases/dirty_test.rb +163 -0
- data/test/cases/finder_respond_to_test.rb +76 -0
- data/test/{finder_test.rb → cases/finder_test.rb} +266 -33
- data/test/{fixtures_test.rb → cases/fixtures_test.rb} +88 -72
- data/test/cases/helper.rb +47 -0
- data/test/{inheritance_test.rb → cases/inheritance_test.rb} +61 -17
- data/test/cases/invalid_date_test.rb +24 -0
- data/test/{json_serialization_test.rb → cases/json_serialization_test.rb} +36 -11
- data/test/{lifecycle_test.rb → cases/lifecycle_test.rb} +16 -13
- data/test/{locking_test.rb → cases/locking_test.rb} +17 -10
- data/test/{method_scoping_test.rb → cases/method_scoping_test.rb} +75 -39
- data/test/{migration_test.rb → cases/migration_test.rb} +420 -80
- data/test/{migration_test_firebird.rb → cases/migration_test_firebird.rb} +3 -3
- data/test/{mixin_test.rb → cases/mixin_test.rb} +7 -6
- data/test/{modules_test.rb → cases/modules_test.rb} +11 -6
- data/test/{multiple_db_test.rb → cases/multiple_db_test.rb} +5 -5
- data/test/cases/named_scope_test.rb +157 -0
- data/test/{pk_test.rb → cases/pk_test.rb} +10 -10
- data/test/{query_cache_test.rb → cases/query_cache_test.rb} +12 -10
- data/test/{readonly_test.rb → cases/readonly_test.rb} +11 -11
- data/test/{reflection_test.rb → cases/reflection_test.rb} +15 -14
- data/test/{reserved_word_test_mysql.rb → cases/reserved_word_test_mysql.rb} +4 -5
- data/test/{schema_authorization_test_postgresql.rb → cases/schema_authorization_test_postgresql.rb} +5 -5
- data/test/cases/schema_dumper_test.rb +138 -0
- data/test/cases/schema_test_postgresql.rb +102 -0
- data/test/{serialization_test.rb → cases/serialization_test.rb} +7 -7
- data/test/{synonym_test_oracle.rb → cases/synonym_test_oracle.rb} +5 -5
- data/test/{table_name_test_sqlserver.rb → cases/table_name_test_sqlserver.rb} +3 -3
- data/test/{threaded_connections_test.rb → cases/threaded_connections_test.rb} +7 -7
- data/test/{transactions_test.rb → cases/transactions_test.rb} +31 -5
- data/test/{unconnected_test.rb → cases/unconnected_test.rb} +2 -2
- data/test/{validations_test.rb → cases/validations_test.rb} +141 -39
- data/test/{xml_serialization_test.rb → cases/xml_serialization_test.rb} +12 -12
- data/test/config.rb +5 -0
- data/test/connections/native_db2/connection.rb +1 -1
- data/test/connections/native_firebird/connection.rb +1 -1
- data/test/connections/native_frontbase/connection.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -1
- data/test/connections/native_openbase/connection.rb +1 -1
- data/test/connections/native_oracle/connection.rb +1 -1
- data/test/connections/native_postgresql/connection.rb +1 -3
- data/test/connections/native_sqlite/connection.rb +2 -2
- data/test/connections/native_sqlite3/connection.rb +2 -2
- data/test/connections/native_sqlite3/in_memory_connection.rb +3 -3
- data/test/connections/native_sybase/connection.rb +1 -1
- data/test/fixtures/author_addresses.yml +5 -0
- data/test/fixtures/authors.yml +2 -0
- data/test/fixtures/clubs.yml +6 -0
- data/test/fixtures/jobs.yml +7 -0
- data/test/fixtures/members.yml +4 -0
- data/test/fixtures/memberships.yml +20 -0
- data/test/fixtures/owners.yml +7 -0
- data/test/fixtures/people.yml +4 -1
- data/test/fixtures/pets.yml +14 -0
- data/test/fixtures/posts.yml +1 -0
- data/test/fixtures/price_estimates.yml +7 -0
- data/test/fixtures/readers.yml +5 -0
- data/test/fixtures/references.yml +17 -0
- data/test/fixtures/sponsors.yml +9 -0
- data/test/fixtures/subscribers.yml +7 -0
- data/test/fixtures/subscriptions.yml +12 -0
- data/test/fixtures/taggings.yml +4 -1
- data/test/fixtures/topics.yml +22 -2
- data/test/fixtures/warehouse-things.yml +3 -0
- data/test/{fixtures/migrations_with_decimal → migrations/decimal}/1_give_me_big_numbers.rb +0 -0
- data/test/{fixtures/migrations_with_duplicate → migrations/duplicate}/1_people_have_last_names.rb +1 -1
- data/test/{fixtures/migrations_with_duplicate → migrations/duplicate}/2_we_need_reminders.rb +1 -1
- data/test/{fixtures/migrations_with_duplicate → migrations/duplicate}/3_foo.rb +0 -0
- data/test/{fixtures/migrations → migrations/duplicate}/3_innocent_jointable.rb +0 -0
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
- data/test/{fixtures/migrations_with_duplicate → migrations/interleaved/pass_1}/3_innocent_jointable.rb +0 -0
- data/test/{fixtures/migrations → migrations/interleaved/pass_2}/1_people_have_last_names.rb +1 -1
- data/test/{fixtures/migrations_with_missing_versions/4_innocent_jointable.rb → migrations/interleaved/pass_2/3_innocent_jointable.rb} +0 -0
- data/test/{fixtures/migrations_with_missing_versions → migrations/interleaved/pass_3}/1_people_have_last_names.rb +1 -1
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
- data/test/{fixtures/migrations_with_missing_versions → migrations/missing}/1000_people_have_middle_names.rb +1 -1
- data/test/migrations/missing/1_people_have_last_names.rb +9 -0
- data/test/{fixtures/migrations_with_missing_versions → migrations/missing}/3_we_need_reminders.rb +1 -1
- data/test/migrations/missing/4_innocent_jointable.rb +12 -0
- data/test/migrations/valid/1_people_have_last_names.rb +9 -0
- data/test/{fixtures/migrations → migrations/valid}/2_we_need_reminders.rb +1 -1
- data/test/migrations/valid/3_innocent_jointable.rb +12 -0
- data/test/{fixtures → models}/author.rb +28 -4
- data/test/{fixtures → models}/auto_id.rb +0 -0
- data/test/{fixtures → models}/binary.rb +0 -0
- data/test/{fixtures → models}/book.rb +0 -0
- data/test/{fixtures → models}/categorization.rb +0 -0
- data/test/{fixtures → models}/category.rb +8 -5
- data/test/{fixtures → models}/citation.rb +0 -0
- data/test/models/club.rb +7 -0
- data/test/{fixtures → models}/column_name.rb +0 -0
- data/test/{fixtures → models}/comment.rb +5 -3
- data/test/{fixtures → models}/company.rb +15 -6
- data/test/{fixtures → models}/company_in_module.rb +5 -3
- data/test/{fixtures → models}/computer.rb +0 -1
- data/test/{fixtures → models}/contact.rb +1 -1
- data/test/{fixtures → models}/course.rb +0 -0
- data/test/{fixtures → models}/customer.rb +8 -8
- data/test/{fixtures → models}/default.rb +0 -0
- data/test/{fixtures → models}/developer.rb +14 -10
- data/test/{fixtures → models}/edge.rb +0 -0
- data/test/{fixtures → models}/entrant.rb +0 -0
- data/test/models/guid.rb +2 -0
- data/test/{fixtures → models}/item.rb +0 -0
- data/test/models/job.rb +5 -0
- data/test/{fixtures → models}/joke.rb +0 -0
- data/test/{fixtures → models}/keyboard.rb +0 -0
- data/test/{fixtures → models}/legacy_thing.rb +0 -0
- data/test/{fixtures → models}/matey.rb +0 -0
- data/test/models/member.rb +9 -0
- data/test/models/membership.rb +9 -0
- data/test/{fixtures → models}/minimalistic.rb +0 -0
- data/test/{fixtures → models}/mixed_case_monkey.rb +0 -0
- data/test/{fixtures → models}/movie.rb +0 -0
- data/test/{fixtures → models}/order.rb +2 -2
- data/test/models/owner.rb +4 -0
- data/test/{fixtures → models}/parrot.rb +0 -0
- data/test/models/person.rb +10 -0
- data/test/models/pet.rb +4 -0
- data/test/models/pirate.rb +9 -0
- data/test/{fixtures → models}/post.rb +23 -2
- data/test/models/price_estimate.rb +3 -0
- data/test/{fixtures → models}/project.rb +1 -0
- data/test/{fixtures → models}/reader.rb +0 -0
- data/test/models/reference.rb +4 -0
- data/test/{fixtures → models}/reply.rb +7 -5
- data/test/{fixtures → models}/ship.rb +0 -0
- data/test/models/sponsor.rb +4 -0
- data/test/{fixtures → models}/subject.rb +0 -0
- data/test/{fixtures → models}/subscriber.rb +2 -0
- data/test/models/subscription.rb +4 -0
- data/test/{fixtures → models}/tag.rb +0 -0
- data/test/{fixtures → models}/tagging.rb +0 -0
- data/test/{fixtures → models}/task.rb +0 -0
- data/test/{fixtures → models}/topic.rb +32 -4
- data/test/{fixtures → models}/treasure.rb +2 -0
- data/test/{fixtures → models}/vertex.rb +0 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/mysql_specific_schema.rb +12 -0
- data/test/schema/postgresql_specific_schema.rb +103 -0
- data/test/schema/schema.rb +421 -0
- data/test/schema/schema2.rb +6 -0
- data/test/schema/sqlite_specific_schema.rb +25 -0
- data/test/schema/sqlserver_specific_schema.rb +5 -0
- metadata +192 -176
- data/test/aaa_create_tables_test.rb +0 -72
- data/test/abstract_unit.rb +0 -84
- data/test/active_schema_test_mysql.rb +0 -46
- data/test/all.sh +0 -8
- data/test/association_inheritance_reload.rb +0 -14
- data/test/associations_test.rb +0 -2177
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +0 -1
- data/test/fixtures/bad_fixtures/attr_with_spaces +0 -1
- data/test/fixtures/bad_fixtures/blank_line +0 -3
- data/test/fixtures/bad_fixtures/duplicate_attributes +0 -3
- data/test/fixtures/bad_fixtures/missing_value +0 -1
- data/test/fixtures/db_definitions/db2.drop.sql +0 -33
- data/test/fixtures/db_definitions/db2.sql +0 -235
- data/test/fixtures/db_definitions/db22.drop.sql +0 -2
- data/test/fixtures/db_definitions/db22.sql +0 -5
- data/test/fixtures/db_definitions/firebird.drop.sql +0 -65
- data/test/fixtures/db_definitions/firebird.sql +0 -310
- data/test/fixtures/db_definitions/firebird2.drop.sql +0 -2
- data/test/fixtures/db_definitions/firebird2.sql +0 -6
- data/test/fixtures/db_definitions/frontbase.drop.sql +0 -33
- data/test/fixtures/db_definitions/frontbase.sql +0 -273
- data/test/fixtures/db_definitions/frontbase2.drop.sql +0 -1
- data/test/fixtures/db_definitions/frontbase2.sql +0 -4
- data/test/fixtures/db_definitions/openbase.drop.sql +0 -2
- data/test/fixtures/db_definitions/openbase.sql +0 -318
- data/test/fixtures/db_definitions/openbase2.drop.sql +0 -2
- data/test/fixtures/db_definitions/openbase2.sql +0 -7
- data/test/fixtures/db_definitions/oracle.drop.sql +0 -67
- data/test/fixtures/db_definitions/oracle.sql +0 -330
- data/test/fixtures/db_definitions/oracle2.drop.sql +0 -2
- data/test/fixtures/db_definitions/oracle2.sql +0 -6
- data/test/fixtures/db_definitions/postgresql.drop.sql +0 -44
- data/test/fixtures/db_definitions/postgresql.sql +0 -292
- data/test/fixtures/db_definitions/postgresql2.drop.sql +0 -2
- data/test/fixtures/db_definitions/postgresql2.sql +0 -4
- data/test/fixtures/db_definitions/schema.rb +0 -354
- data/test/fixtures/db_definitions/schema2.rb +0 -11
- data/test/fixtures/db_definitions/sqlite.drop.sql +0 -33
- data/test/fixtures/db_definitions/sqlite.sql +0 -219
- data/test/fixtures/db_definitions/sqlite2.drop.sql +0 -2
- data/test/fixtures/db_definitions/sqlite2.sql +0 -5
- data/test/fixtures/db_definitions/sybase.drop.sql +0 -35
- data/test/fixtures/db_definitions/sybase.sql +0 -222
- data/test/fixtures/db_definitions/sybase2.drop.sql +0 -4
- data/test/fixtures/db_definitions/sybase2.sql +0 -5
- data/test/fixtures/developers_projects/david_action_controller +0 -3
- data/test/fixtures/developers_projects/david_active_record +0 -3
- data/test/fixtures/developers_projects/jamis_active_record +0 -2
- data/test/fixtures/person.rb +0 -4
- data/test/fixtures/pirate.rb +0 -5
- data/test/fixtures/subscribers/first +0 -2
- data/test/fixtures/subscribers/second +0 -2
- data/test/schema_dumper_test.rb +0 -131
- data/test/schema_test_postgresql.rb +0 -64
@@ -0,0 +1,74 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/club'
|
3
|
+
require 'models/member'
|
4
|
+
require 'models/membership'
|
5
|
+
require 'models/sponsor'
|
6
|
+
|
7
|
+
class HasOneThroughAssociationsTest < ActiveRecord::TestCase
|
8
|
+
fixtures :members, :clubs, :memberships, :sponsors
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@member = members(:groucho)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_has_one_through_with_has_one
|
15
|
+
assert_equal clubs(:boring_club), @member.club
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_has_one_through_with_has_many
|
19
|
+
assert_equal clubs(:moustache_club), @member.favourite_club
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_creating_association_creates_through_record
|
23
|
+
new_member = Member.create(:name => "Chris")
|
24
|
+
new_member.club = Club.create(:name => "LRUG")
|
25
|
+
assert_not_nil new_member.current_membership
|
26
|
+
assert_not_nil new_member.club
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_replace_target_record
|
30
|
+
new_club = Club.create(:name => "Marx Bros")
|
31
|
+
@member.club = new_club
|
32
|
+
@member.reload
|
33
|
+
assert_equal new_club, @member.club
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_replacing_target_record_deletes_old_association
|
37
|
+
assert_no_difference "Membership.count" do
|
38
|
+
new_club = Club.create(:name => "Bananarama")
|
39
|
+
@member.club = new_club
|
40
|
+
@member.reload
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_has_one_through_polymorphic
|
45
|
+
assert_equal clubs(:moustache_club), @member.sponsor_club
|
46
|
+
end
|
47
|
+
|
48
|
+
def has_one_through_to_has_many
|
49
|
+
assert_equal 2, @member.fellow_members.size
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_has_one_through_eager_loading
|
53
|
+
members = Member.find(:all, :include => :club, :conditions => ["name = ?", "Groucho Marx"])
|
54
|
+
assert_equal 1, members.size
|
55
|
+
assert_not_nil assert_no_queries {members[0].club}
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_has_one_through_eager_loading_through_polymorphic
|
59
|
+
members = Member.find(:all, :include => :sponsor_club, :conditions => ["name = ?", "Groucho Marx"])
|
60
|
+
assert_equal 1, members.size
|
61
|
+
assert_not_nil assert_no_queries {members[0].sponsor_club}
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_has_one_through_polymorphic_with_source_type
|
65
|
+
assert_equal members(:groucho), clubs(:moustache_club).sponsored_member
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_eager_has_one_through_polymorphic_with_source_type
|
69
|
+
clubs = Club.find(:all, :include => :sponsored_member, :conditions => ["name = ?","Moustache and Eyebrow Fancier Club"])
|
70
|
+
# Only the eyebrow fanciers club has a sponsored_member
|
71
|
+
assert_not_nil assert_no_queries {clubs[0].sponsored_member}
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
require
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/post'
|
3
|
+
require 'models/comment'
|
4
|
+
require 'models/author'
|
5
|
+
require 'models/category'
|
6
|
+
require 'models/categorization'
|
7
7
|
|
8
|
-
class InnerJoinAssociationTest <
|
8
|
+
class InnerJoinAssociationTest < ActiveRecord::TestCase
|
9
9
|
fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations
|
10
10
|
|
11
11
|
def test_construct_finder_sql_creates_inner_joins
|
12
12
|
sql = Author.send(:construct_finder_sql, :joins => :posts)
|
13
|
-
assert_match /INNER JOIN
|
13
|
+
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def test_construct_finder_sql_cascades_inner_joins
|
17
17
|
sql = Author.send(:construct_finder_sql, :joins => {:posts => :comments})
|
18
|
-
assert_match /INNER JOIN
|
19
|
-
assert_match /INNER JOIN
|
18
|
+
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
|
19
|
+
assert_match /INNER JOIN .?comments.? ON .?comments.?.post_id = posts.id/, sql
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def test_construct_finder_sql_inner_joins_through_associations
|
23
23
|
sql = Author.send(:construct_finder_sql, :joins => :categorized_posts)
|
24
|
-
assert_match /INNER JOIN
|
24
|
+
assert_match /INNER JOIN .?categorizations.?.*INNER JOIN .?posts.?/, sql
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def test_construct_finder_sql_applies_association_conditions
|
28
28
|
sql = Author.send(:construct_finder_sql, :joins => :categories_like_general, :conditions => "TERMINATING_MARKER")
|
29
|
-
assert_match /INNER JOIN
|
29
|
+
assert_match /INNER JOIN .?categories.? ON.*AND.*.?General.?.*TERMINATING_MARKER/, sql
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_construct_finder_sql_unpacks_nested_joins
|
33
33
|
sql = Author.send(:construct_finder_sql, :joins => {:posts => [[:comments]]})
|
34
34
|
assert_no_match /inner join.*inner join.*inner join/i, sql, "only two join clauses should be present"
|
35
|
-
assert_match /INNER JOIN
|
36
|
-
assert_match /INNER JOIN
|
35
|
+
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
|
36
|
+
assert_match /INNER JOIN .?comments.? ON .?comments.?.post_id = .?posts.?.id/, sql
|
37
37
|
end
|
38
38
|
|
39
39
|
def test_construct_finder_sql_ignores_empty_joins_hash
|
@@ -51,7 +51,7 @@ class InnerJoinAssociationTest < Test::Unit::TestCase
|
|
51
51
|
assert !authors.empty?, "expected authors to be non-empty"
|
52
52
|
assert authors.all? {|a| a.readonly? }, "expected all authors to be readonly"
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
def test_find_with_implicit_inner_joins_honors_readonly_with_select
|
56
56
|
authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
|
57
57
|
assert !authors.empty?, "expected authors to be non-empty"
|
@@ -67,9 +67,9 @@ class InnerJoinAssociationTest < Test::Unit::TestCase
|
|
67
67
|
def test_find_with_implicit_inner_joins_does_not_set_associations
|
68
68
|
authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
|
69
69
|
assert !authors.empty?, "expected authors to be non-empty"
|
70
|
-
assert authors.all? {|a| !a.send(:
|
70
|
+
assert authors.all? {|a| !a.send(:instance_variable_names).include?("@posts")}, "expected no authors to have the @posts association loaded"
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def test_count_honors_implicit_inner_joins
|
74
74
|
real_count = Author.find(:all).sum{|a| a.posts.count }
|
75
75
|
assert_equal real_count, Author.count(:joins => :posts), "plain inner join count should match the number of referenced posts records"
|
@@ -1,18 +1,18 @@
|
|
1
|
-
require
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
7
|
-
require '
|
8
|
-
require '
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require '
|
13
|
-
require '
|
14
|
-
|
15
|
-
class AssociationsJoinModelTest <
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/tag'
|
3
|
+
require 'models/tagging'
|
4
|
+
require 'models/post'
|
5
|
+
require 'models/item'
|
6
|
+
require 'models/comment'
|
7
|
+
require 'models/author'
|
8
|
+
require 'models/category'
|
9
|
+
require 'models/categorization'
|
10
|
+
require 'models/vertex'
|
11
|
+
require 'models/edge'
|
12
|
+
require 'models/book'
|
13
|
+
require 'models/citation'
|
14
|
+
|
15
|
+
class AssociationsJoinModelTest < ActiveRecord::TestCase
|
16
16
|
self.use_transactional_fixtures = false
|
17
17
|
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
|
18
18
|
|
@@ -32,7 +32,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
32
32
|
assert_equal 2, authors(:mary).categorized_posts.size
|
33
33
|
assert_equal 1, authors(:mary).unique_categorized_posts.size
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def test_has_many_uniq_through_count
|
37
37
|
author = authors(:mary)
|
38
38
|
assert !authors(:mary).unique_categorized_posts.loaded?
|
@@ -42,6 +42,14 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
42
42
|
assert !authors(:mary).unique_categorized_posts.loaded?
|
43
43
|
end
|
44
44
|
|
45
|
+
def test_has_many_uniq_through_find
|
46
|
+
assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_has_many_uniq_through_dynamic_find
|
50
|
+
assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size
|
51
|
+
end
|
52
|
+
|
45
53
|
def test_polymorphic_has_many
|
46
54
|
assert posts(:welcome).taggings.include?(taggings(:welcome_general))
|
47
55
|
end
|
@@ -107,7 +115,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
107
115
|
def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
|
108
116
|
post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
|
109
117
|
assert_instance_of SubStiPost, post
|
110
|
-
|
118
|
+
|
111
119
|
tagging = tags(:misc).taggings.create(:taggable => post)
|
112
120
|
assert_equal "SubStiPost", tagging.taggable_type
|
113
121
|
end
|
@@ -123,7 +131,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
123
131
|
def test_polymorphic_has_many_create_model_with_inheritance
|
124
132
|
post = posts(:thinking)
|
125
133
|
assert_instance_of SpecialPost, post
|
126
|
-
|
134
|
+
|
127
135
|
tagging = tags(:misc).taggings.create(:taggable => post)
|
128
136
|
assert_equal "Post", tagging.taggable_type
|
129
137
|
end
|
@@ -151,7 +159,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
151
159
|
assert_equal "Post", tagging.taggable_type
|
152
160
|
assert_equal old_count+1, posts(:welcome).taggings.count
|
153
161
|
end
|
154
|
-
|
162
|
+
|
155
163
|
def test_create_bang_polymorphic_with_has_many_scope
|
156
164
|
old_count = posts(:welcome).taggings.count
|
157
165
|
tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
|
@@ -241,7 +249,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
241
249
|
assert_equal tagging, post.tagging
|
242
250
|
end
|
243
251
|
end
|
244
|
-
|
252
|
+
|
245
253
|
def test_include_polymorphic_has_one_defined_in_abstract_parent
|
246
254
|
item = Item.find_by_id(items(:dvd).id, :include => :tagging)
|
247
255
|
tagging = taggings(:godfather)
|
@@ -249,7 +257,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
249
257
|
assert_equal tagging, item.tagging
|
250
258
|
end
|
251
259
|
end
|
252
|
-
|
260
|
+
|
253
261
|
def test_include_polymorphic_has_many_through
|
254
262
|
posts = Post.find(:all, :order => 'posts.id')
|
255
263
|
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
@@ -271,7 +279,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
271
279
|
def test_has_many_find_all
|
272
280
|
assert_equal [categories(:general)], authors(:david).categories.find(:all)
|
273
281
|
end
|
274
|
-
|
282
|
+
|
275
283
|
def test_has_many_find_first
|
276
284
|
assert_equal categories(:general), authors(:david).categories.find(:first)
|
277
285
|
end
|
@@ -279,7 +287,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
279
287
|
def test_has_many_with_hash_conditions
|
280
288
|
assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
|
281
289
|
end
|
282
|
-
|
290
|
+
|
283
291
|
def test_has_many_find_conditions
|
284
292
|
assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
|
285
293
|
assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
|
@@ -290,10 +298,23 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
290
298
|
assert_equal nil, authors(:david).categories.find_by_name('Technology')
|
291
299
|
end
|
292
300
|
|
301
|
+
def test_has_many_array_methods_called_by_method_missing
|
302
|
+
assert true, authors(:david).categories.any? { |category| category.name == 'General' }
|
303
|
+
assert_nothing_raised { authors(:david).categories.sort }
|
304
|
+
end
|
305
|
+
|
293
306
|
def test_has_many_going_through_join_model_with_custom_foreign_key
|
294
307
|
assert_equal [], posts(:thinking).authors
|
295
308
|
assert_equal [authors(:mary)], posts(:authorless).authors
|
296
309
|
end
|
310
|
+
|
311
|
+
def test_both_scoped_and_explicit_joins_should_be_respected
|
312
|
+
assert_nothing_raised do
|
313
|
+
Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
|
314
|
+
Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
297
318
|
|
298
319
|
def test_belongs_to_polymorphic_with_counter_cache
|
299
320
|
assert_equal 0, posts(:welcome)[:taggings_count]
|
@@ -317,10 +338,10 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
317
338
|
assert_equal posts(:welcome, :thinking), tags(:general).taggables
|
318
339
|
end
|
319
340
|
assert_raise ActiveRecord::EagerLoadPolymorphicError do
|
320
|
-
assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable)
|
341
|
+
assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
|
321
342
|
end
|
322
343
|
end
|
323
|
-
|
344
|
+
|
324
345
|
def test_has_many_polymorphic_with_source_type
|
325
346
|
assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
|
326
347
|
end
|
@@ -331,6 +352,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
331
352
|
assert_no_queries do
|
332
353
|
assert_equal desired, tag_with_include.tagged_posts
|
333
354
|
end
|
355
|
+
assert_equal 5, tag_with_include.taggings.length
|
334
356
|
end
|
335
357
|
|
336
358
|
def test_has_many_through_has_many_find_all
|
@@ -385,7 +407,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
385
407
|
assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id)
|
386
408
|
end
|
387
409
|
end
|
388
|
-
|
410
|
+
|
389
411
|
def test_eager_load_has_many_through_has_many_with_conditions
|
390
412
|
post = Post.find(:first, :include => :invalid_tags)
|
391
413
|
assert_no_queries do
|
@@ -410,7 +432,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
410
432
|
authors(:david).author_favorites.create :favorite_author => new_author
|
411
433
|
assert_equal new_author, authors(:david).reload.favorite_authors.first
|
412
434
|
end
|
413
|
-
|
435
|
+
|
414
436
|
def test_has_many_through_uses_conditions_specified_on_the_has_many_association
|
415
437
|
author = Author.find(:first)
|
416
438
|
assert !author.comments.blank?
|
@@ -421,11 +443,33 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
421
443
|
assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
|
422
444
|
end
|
423
445
|
|
424
|
-
def
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
446
|
+
def test_associating_unsaved_records_with_has_many_through
|
447
|
+
saved_post = posts(:thinking)
|
448
|
+
new_tag = Tag.new(:name => "new")
|
449
|
+
|
450
|
+
saved_post.tags << new_tag
|
451
|
+
assert !new_tag.new_record? #consistent with habtm!
|
452
|
+
assert !saved_post.new_record?
|
453
|
+
assert saved_post.tags.include?(new_tag)
|
454
|
+
|
455
|
+
assert !new_tag.new_record?
|
456
|
+
assert saved_post.reload.tags(true).include?(new_tag)
|
457
|
+
|
458
|
+
|
459
|
+
new_post = Post.new(:title => "Association replacmenet works!", :body => "You best believe it.")
|
460
|
+
saved_tag = tags(:general)
|
461
|
+
|
462
|
+
new_post.tags << saved_tag
|
463
|
+
assert new_post.new_record?
|
464
|
+
assert !saved_tag.new_record?
|
465
|
+
assert new_post.tags.include?(saved_tag)
|
466
|
+
|
467
|
+
new_post.save!
|
468
|
+
assert !new_post.new_record?
|
469
|
+
assert new_post.reload.tags(true).include?(saved_tag)
|
470
|
+
|
471
|
+
assert posts(:thinking).tags.build.new_record?
|
472
|
+
assert posts(:thinking).tags.new.new_record?
|
429
473
|
end
|
430
474
|
|
431
475
|
def test_create_associate_when_adding_to_has_many_through
|
@@ -504,11 +548,13 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
504
548
|
tag = Tag.create!(:name => 'doomed')
|
505
549
|
post_thinking = posts(:thinking)
|
506
550
|
post_thinking.tags << tag
|
551
|
+
assert_equal(count + 1, post_thinking.taggings(true).size)
|
507
552
|
assert_equal(count + 1, post_thinking.tags(true).size)
|
508
553
|
|
509
|
-
assert_nothing_raised { post_thinking.tags.delete(tag) }
|
554
|
+
assert_nothing_raised { post_thinking.tags.delete(tag) }
|
510
555
|
assert_equal(count, post_thinking.tags.size)
|
511
556
|
assert_equal(count, post_thinking.tags(true).size)
|
557
|
+
assert_equal(count, post_thinking.taggings(true).size)
|
512
558
|
assert_equal(tags_before.sort, post_thinking.tags.sort)
|
513
559
|
end
|
514
560
|
|
@@ -522,7 +568,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
522
568
|
post_thinking.tags << doomed << doomed2
|
523
569
|
assert_equal(count + 2, post_thinking.tags(true).size)
|
524
570
|
|
525
|
-
assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
|
571
|
+
assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
|
526
572
|
assert_equal(count, post_thinking.tags.size)
|
527
573
|
assert_equal(count, post_thinking.tags(true).size)
|
528
574
|
assert_equal(tags_before.sort, post_thinking.tags.sort)
|
@@ -547,13 +593,107 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
547
593
|
def test_has_many_through_has_many_with_sti
|
548
594
|
assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
|
549
595
|
end
|
550
|
-
|
596
|
+
|
551
597
|
def test_uniq_has_many_through_should_retain_order
|
552
598
|
comment_ids = authors(:david).comments.map(&:id)
|
553
599
|
assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
|
554
600
|
assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
|
555
601
|
end
|
556
602
|
|
603
|
+
def test_polymorphic_has_many
|
604
|
+
expected = taggings(:welcome_general)
|
605
|
+
p = Post.find(posts(:welcome).id, :include => :taggings)
|
606
|
+
assert_no_queries {assert p.taggings.include?(expected)}
|
607
|
+
assert posts(:welcome).taggings.include?(taggings(:welcome_general))
|
608
|
+
end
|
609
|
+
|
610
|
+
def test_polymorphic_has_one
|
611
|
+
expected = posts(:welcome)
|
612
|
+
|
613
|
+
tagging = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
|
614
|
+
assert_no_queries { assert_equal expected, tagging.taggable}
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_polymorphic_belongs_to
|
618
|
+
p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
|
619
|
+
assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_preload_polymorphic_has_many_through
|
623
|
+
posts = Post.find(:all, :order => 'posts.id')
|
624
|
+
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
625
|
+
assert_equal posts.length, posts_with_tags.length
|
626
|
+
posts.length.times do |i|
|
627
|
+
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
def test_preload_polymorph_many_types
|
632
|
+
taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel']
|
633
|
+
assert_no_queries do
|
634
|
+
taggings.first.taggable.id
|
635
|
+
taggings[1].taggable.id
|
636
|
+
end
|
637
|
+
|
638
|
+
taggables = taggings.map(&:taggable)
|
639
|
+
assert taggables.include?(items(:dvd))
|
640
|
+
assert taggables.include?(posts(:welcome))
|
641
|
+
end
|
642
|
+
|
643
|
+
def test_preload_nil_polymorphic_belongs_to
|
644
|
+
assert_nothing_raised do
|
645
|
+
taggings = Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
def test_preload_polymorphic_has_many
|
650
|
+
posts = Post.find(:all, :order => 'posts.id')
|
651
|
+
posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
|
652
|
+
assert_equal posts.length, posts_with_taggings.length
|
653
|
+
posts.length.times do |i|
|
654
|
+
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def test_belongs_to_shared_parent
|
659
|
+
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
|
660
|
+
assert_no_queries do
|
661
|
+
assert_equal comments.first.post, comments[1].post
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
def test_has_many_through_include_uses_array_include_after_loaded
|
666
|
+
david = authors(:david)
|
667
|
+
david.categories.class # force load target
|
668
|
+
|
669
|
+
category = david.categories.first
|
670
|
+
|
671
|
+
assert_no_queries do
|
672
|
+
assert david.categories.loaded?
|
673
|
+
assert david.categories.include?(category)
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
def test_has_many_through_include_checks_if_record_exists_if_target_not_loaded
|
678
|
+
david = authors(:david)
|
679
|
+
category = david.categories.first
|
680
|
+
|
681
|
+
david.reload
|
682
|
+
assert ! david.categories.loaded?
|
683
|
+
assert_queries(1) do
|
684
|
+
assert david.categories.include?(category)
|
685
|
+
end
|
686
|
+
assert ! david.categories.loaded?
|
687
|
+
end
|
688
|
+
|
689
|
+
def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping
|
690
|
+
david = authors(:david)
|
691
|
+
category = Category.create!(:name => 'Not Associated')
|
692
|
+
|
693
|
+
assert ! david.categories.loaded?
|
694
|
+
assert ! david.categories.include?(category)
|
695
|
+
end
|
696
|
+
|
557
697
|
private
|
558
698
|
# create dynamic Post models to allow different dependency options
|
559
699
|
def find_post_with_dependency(post_id, association, association_name, dependency)
|