activerecord_csi 2.3.5.p6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +5858 -0
- data/README +351 -0
- data/RUNNING_UNIT_TESTS +36 -0
- data/Rakefile +270 -0
- data/examples/associations.png +0 -0
- data/examples/performance.rb +162 -0
- data/install.rb +30 -0
- data/lib/active_record/aggregations.rb +261 -0
- data/lib/active_record/association_preload.rb +389 -0
- data/lib/active_record/associations/association_collection.rb +475 -0
- data/lib/active_record/associations/association_proxy.rb +278 -0
- data/lib/active_record/associations/belongs_to_association.rb +76 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
- data/lib/active_record/associations/has_many_association.rb +122 -0
- data/lib/active_record/associations/has_many_through_association.rb +266 -0
- data/lib/active_record/associations/has_one_association.rb +133 -0
- data/lib/active_record/associations/has_one_through_association.rb +37 -0
- data/lib/active_record/associations.rb +2241 -0
- data/lib/active_record/attribute_methods.rb +388 -0
- data/lib/active_record/autosave_association.rb +364 -0
- data/lib/active_record/base.rb +3171 -0
- data/lib/active_record/batches.rb +81 -0
- data/lib/active_record/calculations.rb +311 -0
- data/lib/active_record/callbacks.rb +360 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
- data/lib/active_record/dirty.rb +183 -0
- data/lib/active_record/dynamic_finder_match.rb +41 -0
- data/lib/active_record/dynamic_scope_match.rb +25 -0
- data/lib/active_record/fixtures.rb +996 -0
- data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
- data/lib/active_record/locale/en.yml +58 -0
- data/lib/active_record/locking/optimistic.rb +148 -0
- data/lib/active_record/locking/pessimistic.rb +55 -0
- data/lib/active_record/migration.rb +566 -0
- data/lib/active_record/named_scope.rb +192 -0
- data/lib/active_record/nested_attributes.rb +392 -0
- data/lib/active_record/observer.rb +197 -0
- data/lib/active_record/query_cache.rb +33 -0
- data/lib/active_record/reflection.rb +320 -0
- data/lib/active_record/schema.rb +51 -0
- data/lib/active_record/schema_dumper.rb +182 -0
- data/lib/active_record/serialization.rb +101 -0
- data/lib/active_record/serializers/json_serializer.rb +91 -0
- data/lib/active_record/serializers/xml_serializer.rb +357 -0
- data/lib/active_record/session_store.rb +326 -0
- data/lib/active_record/test_case.rb +66 -0
- data/lib/active_record/timestamp.rb +71 -0
- data/lib/active_record/transactions.rb +235 -0
- data/lib/active_record/validations.rb +1135 -0
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record.rb +84 -0
- data/lib/activerecord.rb +2 -0
- data/test/assets/example.log +1 -0
- data/test/assets/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +24 -0
- data/test/cases/active_schema_test_mysql.rb +100 -0
- data/test/cases/active_schema_test_postgresql.rb +24 -0
- data/test/cases/adapter_test.rb +145 -0
- data/test/cases/aggregations_test.rb +167 -0
- data/test/cases/ar_schema_test.rb +32 -0
- data/test/cases/associations/belongs_to_associations_test.rb +425 -0
- data/test/cases/associations/callbacks_test.rb +161 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
- data/test/cases/associations/eager_singularization_test.rb +145 -0
- data/test/cases/associations/eager_test.rb +834 -0
- data/test/cases/associations/extension_test.rb +62 -0
- data/test/cases/associations/habtm_join_table_test.rb +56 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
- data/test/cases/associations/has_many_associations_test.rb +1134 -0
- data/test/cases/associations/has_many_through_associations_test.rb +346 -0
- data/test/cases/associations/has_one_associations_test.rb +330 -0
- data/test/cases/associations/has_one_through_associations_test.rb +209 -0
- data/test/cases/associations/inner_join_association_test.rb +93 -0
- data/test/cases/associations/join_model_test.rb +712 -0
- data/test/cases/associations_test.rb +262 -0
- data/test/cases/attribute_methods_test.rb +305 -0
- data/test/cases/autosave_association_test.rb +1142 -0
- data/test/cases/base_test.rb +2154 -0
- data/test/cases/batches_test.rb +61 -0
- data/test/cases/binary_test.rb +30 -0
- data/test/cases/calculations_test.rb +348 -0
- data/test/cases/callbacks_observers_test.rb +38 -0
- data/test/cases/callbacks_test.rb +438 -0
- data/test/cases/class_inheritable_attributes_test.rb +32 -0
- data/test/cases/column_alias_test.rb +17 -0
- data/test/cases/column_definition_test.rb +70 -0
- data/test/cases/connection_pool_test.rb +25 -0
- data/test/cases/connection_test_firebird.rb +8 -0
- data/test/cases/connection_test_mysql.rb +64 -0
- data/test/cases/copy_table_test_sqlite.rb +80 -0
- data/test/cases/database_statements_test.rb +12 -0
- data/test/cases/datatype_test_postgresql.rb +204 -0
- data/test/cases/date_time_test.rb +37 -0
- data/test/cases/default_test_firebird.rb +16 -0
- data/test/cases/defaults_test.rb +111 -0
- data/test/cases/deprecated_finder_test.rb +30 -0
- data/test/cases/dirty_test.rb +316 -0
- data/test/cases/finder_respond_to_test.rb +76 -0
- data/test/cases/finder_test.rb +1066 -0
- data/test/cases/fixtures_test.rb +656 -0
- data/test/cases/helper.rb +68 -0
- data/test/cases/i18n_test.rb +46 -0
- data/test/cases/inheritance_test.rb +262 -0
- data/test/cases/invalid_date_test.rb +24 -0
- data/test/cases/json_serialization_test.rb +205 -0
- data/test/cases/lifecycle_test.rb +193 -0
- data/test/cases/locking_test.rb +304 -0
- data/test/cases/method_scoping_test.rb +704 -0
- data/test/cases/migration_test.rb +1523 -0
- data/test/cases/migration_test_firebird.rb +124 -0
- data/test/cases/mixin_test.rb +96 -0
- data/test/cases/modules_test.rb +81 -0
- data/test/cases/multiple_db_test.rb +85 -0
- data/test/cases/named_scope_test.rb +361 -0
- data/test/cases/nested_attributes_test.rb +581 -0
- data/test/cases/pk_test.rb +119 -0
- data/test/cases/pooled_connections_test.rb +103 -0
- data/test/cases/query_cache_test.rb +123 -0
- data/test/cases/readonly_test.rb +107 -0
- data/test/cases/reflection_test.rb +194 -0
- data/test/cases/reload_models_test.rb +22 -0
- data/test/cases/repair_helper.rb +50 -0
- data/test/cases/reserved_word_test_mysql.rb +176 -0
- data/test/cases/sanitize_test.rb +25 -0
- data/test/cases/schema_authorization_test_postgresql.rb +75 -0
- data/test/cases/schema_dumper_test.rb +211 -0
- data/test/cases/schema_test_postgresql.rb +178 -0
- data/test/cases/serialization_test.rb +47 -0
- data/test/cases/synonym_test_oracle.rb +17 -0
- data/test/cases/timestamp_test.rb +75 -0
- data/test/cases/transactions_test.rb +522 -0
- data/test/cases/unconnected_test.rb +32 -0
- data/test/cases/validations_i18n_test.rb +955 -0
- data/test/cases/validations_test.rb +1640 -0
- data/test/cases/xml_serialization_test.rb +240 -0
- data/test/config.rb +5 -0
- data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
- data/test/connections/jdbc_jdbch2/connection.rb +18 -0
- data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
- data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
- data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
- data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +25 -0
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +25 -0
- data/test/connections/native_sqlite/connection.rb +25 -0
- data/test/connections/native_sqlite3/connection.rb +25 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/fixtures/accounts.yml +29 -0
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author_addresses.yml +5 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +9 -0
- data/test/fixtures/binaries.yml +132 -0
- data/test/fixtures/books.yml +7 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/clubs.yml +6 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +56 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customers.yml +26 -0
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/jobs.yml +7 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/member_types.yml +6 -0
- data/test/fixtures/members.yml +6 -0
- data/test/fixtures/memberships.yml +20 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixins.yml +29 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/organizations.yml +5 -0
- data/test/fixtures/owners.yml +7 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/people.yml +15 -0
- data/test/fixtures/pets.yml +14 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/posts.yml +52 -0
- data/test/fixtures/price_estimates.yml +7 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/readers.yml +9 -0
- data/test/fixtures/references.yml +17 -0
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ships.yml +5 -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 +28 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topics.yml +42 -0
- data/test/fixtures/toys.yml +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures/warehouse-things.yml +3 -0
- data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
- data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
- data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
- data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
- data/test/migrations/duplicate/3_foo.rb +7 -0
- data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
- data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
- data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
- data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
- data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
- 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/migrations/missing/1000_people_have_middle_names.rb +9 -0
- data/test/migrations/missing/1_people_have_last_names.rb +9 -0
- data/test/migrations/missing/3_we_need_reminders.rb +12 -0
- data/test/migrations/missing/4_innocent_jointable.rb +12 -0
- data/test/migrations/valid/1_people_have_last_names.rb +9 -0
- data/test/migrations/valid/2_we_need_reminders.rb +12 -0
- data/test/migrations/valid/3_innocent_jointable.rb +12 -0
- data/test/models/author.rb +146 -0
- data/test/models/auto_id.rb +4 -0
- data/test/models/binary.rb +2 -0
- data/test/models/bird.rb +3 -0
- data/test/models/book.rb +4 -0
- data/test/models/categorization.rb +5 -0
- data/test/models/category.rb +34 -0
- data/test/models/citation.rb +6 -0
- data/test/models/club.rb +13 -0
- data/test/models/column_name.rb +3 -0
- data/test/models/comment.rb +29 -0
- data/test/models/company.rb +171 -0
- data/test/models/company_in_module.rb +61 -0
- data/test/models/computer.rb +3 -0
- data/test/models/contact.rb +16 -0
- data/test/models/contract.rb +5 -0
- data/test/models/course.rb +3 -0
- data/test/models/customer.rb +73 -0
- data/test/models/default.rb +2 -0
- data/test/models/developer.rb +101 -0
- data/test/models/edge.rb +5 -0
- data/test/models/entrant.rb +3 -0
- data/test/models/essay.rb +3 -0
- data/test/models/event.rb +3 -0
- data/test/models/guid.rb +2 -0
- data/test/models/item.rb +7 -0
- data/test/models/job.rb +5 -0
- data/test/models/joke.rb +3 -0
- data/test/models/keyboard.rb +3 -0
- data/test/models/legacy_thing.rb +3 -0
- data/test/models/matey.rb +4 -0
- data/test/models/member.rb +12 -0
- data/test/models/member_detail.rb +5 -0
- data/test/models/member_type.rb +3 -0
- data/test/models/membership.rb +9 -0
- data/test/models/minimalistic.rb +2 -0
- data/test/models/mixed_case_monkey.rb +3 -0
- data/test/models/movie.rb +5 -0
- data/test/models/order.rb +4 -0
- data/test/models/organization.rb +6 -0
- data/test/models/owner.rb +5 -0
- data/test/models/parrot.rb +16 -0
- data/test/models/person.rb +16 -0
- data/test/models/pet.rb +5 -0
- data/test/models/pirate.rb +70 -0
- data/test/models/post.rb +100 -0
- data/test/models/price_estimate.rb +3 -0
- data/test/models/project.rb +30 -0
- data/test/models/reader.rb +4 -0
- data/test/models/reference.rb +4 -0
- data/test/models/reply.rb +46 -0
- data/test/models/ship.rb +10 -0
- data/test/models/ship_part.rb +5 -0
- data/test/models/sponsor.rb +4 -0
- data/test/models/subject.rb +4 -0
- data/test/models/subscriber.rb +8 -0
- data/test/models/subscription.rb +4 -0
- data/test/models/tag.rb +7 -0
- data/test/models/tagging.rb +10 -0
- data/test/models/task.rb +3 -0
- data/test/models/topic.rb +80 -0
- data/test/models/toy.rb +6 -0
- data/test/models/treasure.rb +8 -0
- data/test/models/vertex.rb +9 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/mysql_specific_schema.rb +24 -0
- data/test/schema/postgresql_specific_schema.rb +114 -0
- data/test/schema/schema.rb +493 -0
- data/test/schema/schema2.rb +6 -0
- data/test/schema/sqlite_specific_schema.rb +25 -0
- metadata +420 -0
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
require "cases/helper"
|
|
2
|
+
require "models/pirate"
|
|
3
|
+
require "models/ship"
|
|
4
|
+
require "models/bird"
|
|
5
|
+
require "models/parrot"
|
|
6
|
+
require "models/treasure"
|
|
7
|
+
|
|
8
|
+
module AssertRaiseWithMessage
|
|
9
|
+
def assert_raise_with_message(expected_exception, expected_message)
|
|
10
|
+
begin
|
|
11
|
+
error_raised = false
|
|
12
|
+
yield
|
|
13
|
+
rescue expected_exception => error
|
|
14
|
+
error_raised = true
|
|
15
|
+
actual_message = error.message
|
|
16
|
+
end
|
|
17
|
+
assert error_raised
|
|
18
|
+
assert_equal expected_message, actual_message
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class TestNestedAttributesInGeneral < ActiveRecord::TestCase
|
|
23
|
+
include AssertRaiseWithMessage
|
|
24
|
+
|
|
25
|
+
def teardown
|
|
26
|
+
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_base_should_have_an_empty_nested_attributes_options
|
|
30
|
+
assert_equal Hash.new, ActiveRecord::Base.nested_attributes_options
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_should_add_a_proc_to_nested_attributes_options
|
|
34
|
+
[:parrots, :birds].each do |name|
|
|
35
|
+
assert_instance_of Proc, Pirate.nested_attributes_options[name][:reject_if]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_should_raise_an_ArgumentError_for_non_existing_associations
|
|
40
|
+
assert_raise_with_message ArgumentError, "No association found for name `honesty'. Has it been defined yet?" do
|
|
41
|
+
Pirate.accepts_nested_attributes_for :honesty
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_should_disable_allow_destroy_by_default
|
|
46
|
+
Pirate.accepts_nested_attributes_for :ship
|
|
47
|
+
|
|
48
|
+
pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
|
49
|
+
ship = pirate.create_ship(:name => 'Nights Dirty Lightning')
|
|
50
|
+
|
|
51
|
+
assert_no_difference('Ship.count') do
|
|
52
|
+
pirate.update_attributes(:ship_attributes => { '_destroy' => true })
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_a_model_should_respond_to_underscore_destroy_and_return_if_it_is_marked_for_destruction
|
|
57
|
+
ship = Ship.create!(:name => 'Nights Dirty Lightning')
|
|
58
|
+
assert !ship._destroy
|
|
59
|
+
ship.mark_for_destruction
|
|
60
|
+
assert ship._destroy
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_underscore_delete_is_deprecated
|
|
64
|
+
ActiveSupport::Deprecation.expects(:warn)
|
|
65
|
+
ship = Ship.create!(:name => 'Nights Dirty Lightning')
|
|
66
|
+
ship._delete
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_reject_if_method_without_arguments
|
|
70
|
+
Pirate.accepts_nested_attributes_for :ship, :reject_if => :new_record?
|
|
71
|
+
|
|
72
|
+
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
|
73
|
+
pirate.ship_attributes = { :name => 'Black Pearl' }
|
|
74
|
+
assert_no_difference('Ship.count') { pirate.save! }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_reject_if_method_with_arguments
|
|
78
|
+
Pirate.accepts_nested_attributes_for :ship, :reject_if => :reject_empty_ships_on_create
|
|
79
|
+
|
|
80
|
+
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
|
81
|
+
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
|
82
|
+
assert_no_difference('Ship.count') { pirate.save! }
|
|
83
|
+
|
|
84
|
+
# pirate.reject_empty_ships_on_create returns false for saved records
|
|
85
|
+
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
|
86
|
+
assert_difference('Ship.count') { pirate.save! }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_reject_if_with_indifferent_keys
|
|
90
|
+
Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:name].blank? }
|
|
91
|
+
|
|
92
|
+
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
|
93
|
+
pirate.ship_attributes = { :name => 'Hello Pearl' }
|
|
94
|
+
assert_difference('Ship.count') { pirate.save! }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
|
99
|
+
include AssertRaiseWithMessage
|
|
100
|
+
|
|
101
|
+
def setup
|
|
102
|
+
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
|
103
|
+
@ship = @pirate.create_ship(:name => 'Nights Dirty Lightning')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_should_raise_argument_error_if_trying_to_build_polymorphic_belongs_to
|
|
107
|
+
assert_raise_with_message ArgumentError, "Cannot build association looter. Are you trying to build a polymorphic one-to-one association?" do
|
|
108
|
+
Treasure.new(:name => 'pearl', :looter_attributes => {:catchphrase => "Arrr"})
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_should_define_an_attribute_writer_method_for_the_association
|
|
113
|
+
assert_respond_to @pirate, :ship_attributes=
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_should_build_a_new_record_if_there_is_no_id
|
|
117
|
+
@ship.destroy
|
|
118
|
+
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' }
|
|
119
|
+
|
|
120
|
+
assert @pirate.ship.new_record?
|
|
121
|
+
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy
|
|
125
|
+
@ship.destroy
|
|
126
|
+
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' }
|
|
127
|
+
|
|
128
|
+
assert_nil @pirate.ship
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_should_not_build_a_new_record_if_a_reject_if_proc_returns_false
|
|
132
|
+
@ship.destroy
|
|
133
|
+
@pirate.reload.ship_attributes = {}
|
|
134
|
+
|
|
135
|
+
assert_nil @pirate.ship
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_should_replace_an_existing_record_if_there_is_no_id
|
|
139
|
+
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' }
|
|
140
|
+
|
|
141
|
+
assert @pirate.ship.new_record?
|
|
142
|
+
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
|
143
|
+
assert_equal 'Nights Dirty Lightning', @ship.name
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy
|
|
147
|
+
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' }
|
|
148
|
+
|
|
149
|
+
assert_equal @ship, @pirate.ship
|
|
150
|
+
assert_equal 'Nights Dirty Lightning', @pirate.ship.name
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def test_should_modify_an_existing_record_if_there_is_a_matching_id
|
|
154
|
+
@pirate.reload.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' }
|
|
155
|
+
|
|
156
|
+
assert_equal @ship, @pirate.ship
|
|
157
|
+
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
|
161
|
+
@pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' }
|
|
162
|
+
|
|
163
|
+
assert_equal @ship, @pirate.ship
|
|
164
|
+
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id
|
|
168
|
+
@ship.stubs(:id).returns('ABC1X')
|
|
169
|
+
@pirate.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' }
|
|
170
|
+
|
|
171
|
+
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
|
|
175
|
+
@pirate.ship.destroy
|
|
176
|
+
[1, '1', true, 'true'].each do |truth|
|
|
177
|
+
@pirate.reload.create_ship(:name => 'Mister Pablo')
|
|
178
|
+
assert_difference('Ship.count', -1) do
|
|
179
|
+
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => truth })
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
|
|
185
|
+
[nil, '0', 0, 'false', false].each do |not_truth|
|
|
186
|
+
assert_no_difference('Ship.count') do
|
|
187
|
+
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => not_truth })
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
|
|
193
|
+
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
|
|
194
|
+
|
|
195
|
+
assert_no_difference('Ship.count') do
|
|
196
|
+
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => '1' })
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def test_should_also_work_with_a_HashWithIndifferentAccess
|
|
203
|
+
@pirate.ship_attributes = HashWithIndifferentAccess.new(:id => @ship.id, :name => 'Davy Jones Gold Dagger')
|
|
204
|
+
|
|
205
|
+
assert !@pirate.ship.new_record?
|
|
206
|
+
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def test_should_work_with_update_attributes_as_well
|
|
210
|
+
@pirate.update_attributes({ :catchphrase => 'Arr', :ship_attributes => { :id => @ship.id, :name => 'Mister Pablo' } })
|
|
211
|
+
@pirate.reload
|
|
212
|
+
|
|
213
|
+
assert_equal 'Arr', @pirate.catchphrase
|
|
214
|
+
assert_equal 'Mister Pablo', @pirate.ship.name
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
|
218
|
+
assert_no_difference('Ship.count') do
|
|
219
|
+
@pirate.attributes = { :ship_attributes => { :id => @ship.id, :_destroy => '1' } }
|
|
220
|
+
end
|
|
221
|
+
assert_difference('Ship.count', -1) do
|
|
222
|
+
@pirate.save
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def test_should_automatically_enable_autosave_on_the_association
|
|
227
|
+
assert Pirate.reflect_on_association(:ship).options[:autosave]
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
|
232
|
+
def setup
|
|
233
|
+
@ship = Ship.new(:name => 'Nights Dirty Lightning')
|
|
234
|
+
@pirate = @ship.build_pirate(:catchphrase => 'Aye')
|
|
235
|
+
@ship.save!
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def test_should_define_an_attribute_writer_method_for_the_association
|
|
239
|
+
assert_respond_to @ship, :pirate_attributes=
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def test_should_build_a_new_record_if_there_is_no_id
|
|
243
|
+
@pirate.destroy
|
|
244
|
+
@ship.reload.pirate_attributes = { :catchphrase => 'Arr' }
|
|
245
|
+
|
|
246
|
+
assert @ship.pirate.new_record?
|
|
247
|
+
assert_equal 'Arr', @ship.pirate.catchphrase
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy
|
|
251
|
+
@pirate.destroy
|
|
252
|
+
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' }
|
|
253
|
+
|
|
254
|
+
assert_nil @ship.pirate
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def test_should_not_build_a_new_record_if_a_reject_if_proc_returns_false
|
|
258
|
+
@pirate.destroy
|
|
259
|
+
@ship.reload.pirate_attributes = {}
|
|
260
|
+
|
|
261
|
+
assert_nil @ship.pirate
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def test_should_replace_an_existing_record_if_there_is_no_id
|
|
265
|
+
@ship.reload.pirate_attributes = { :catchphrase => 'Arr' }
|
|
266
|
+
|
|
267
|
+
assert @ship.pirate.new_record?
|
|
268
|
+
assert_equal 'Arr', @ship.pirate.catchphrase
|
|
269
|
+
assert_equal 'Aye', @pirate.catchphrase
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy
|
|
273
|
+
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' }
|
|
274
|
+
|
|
275
|
+
assert_equal @pirate, @ship.pirate
|
|
276
|
+
assert_equal 'Aye', @ship.pirate.catchphrase
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def test_should_modify_an_existing_record_if_there_is_a_matching_id
|
|
280
|
+
@ship.reload.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' }
|
|
281
|
+
|
|
282
|
+
assert_equal @pirate, @ship.pirate
|
|
283
|
+
assert_equal 'Arr', @ship.pirate.catchphrase
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
|
287
|
+
@ship.reload.pirate_attributes = { 'id' => @pirate.id, 'catchphrase' => 'Arr' }
|
|
288
|
+
|
|
289
|
+
assert_equal @pirate, @ship.pirate
|
|
290
|
+
assert_equal 'Arr', @ship.pirate.catchphrase
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id
|
|
294
|
+
@pirate.stubs(:id).returns('ABC1X')
|
|
295
|
+
@ship.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' }
|
|
296
|
+
|
|
297
|
+
assert_equal 'Arr', @ship.pirate.catchphrase
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
|
|
301
|
+
@ship.pirate.destroy
|
|
302
|
+
[1, '1', true, 'true'].each do |truth|
|
|
303
|
+
@ship.reload.create_pirate(:catchphrase => 'Arr')
|
|
304
|
+
assert_difference('Pirate.count', -1) do
|
|
305
|
+
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => truth })
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
|
|
311
|
+
[nil, '0', 0, 'false', false].each do |not_truth|
|
|
312
|
+
assert_no_difference('Pirate.count') do
|
|
313
|
+
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => not_truth })
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
|
|
319
|
+
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
|
|
320
|
+
|
|
321
|
+
assert_no_difference('Pirate.count') do
|
|
322
|
+
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => '1' })
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def test_should_work_with_update_attributes_as_well
|
|
329
|
+
@ship.update_attributes({ :name => 'Mister Pablo', :pirate_attributes => { :catchphrase => 'Arr' } })
|
|
330
|
+
@ship.reload
|
|
331
|
+
|
|
332
|
+
assert_equal 'Mister Pablo', @ship.name
|
|
333
|
+
assert_equal 'Arr', @ship.pirate.catchphrase
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
|
337
|
+
assert_no_difference('Pirate.count') do
|
|
338
|
+
@ship.attributes = { :pirate_attributes => { :id => @ship.pirate.id, '_destroy' => true } }
|
|
339
|
+
end
|
|
340
|
+
assert_difference('Pirate.count', -1) { @ship.save }
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def test_should_automatically_enable_autosave_on_the_association
|
|
344
|
+
assert Ship.reflect_on_association(:pirate).options[:autosave]
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
module NestedAttributesOnACollectionAssociationTests
|
|
349
|
+
include AssertRaiseWithMessage
|
|
350
|
+
|
|
351
|
+
def test_should_define_an_attribute_writer_method_for_the_association
|
|
352
|
+
assert_respond_to @pirate, association_setter
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def test_should_take_a_hash_with_string_keys_and_assign_the_attributes_to_the_associated_models
|
|
356
|
+
@alternate_params[association_getter].stringify_keys!
|
|
357
|
+
@pirate.update_attributes @alternate_params
|
|
358
|
+
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def test_should_take_an_array_and_assign_the_attributes_to_the_associated_models
|
|
362
|
+
@pirate.send(association_setter, @alternate_params[association_getter].values)
|
|
363
|
+
@pirate.save
|
|
364
|
+
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def test_should_also_work_with_a_HashWithIndifferentAccess
|
|
368
|
+
@pirate.send(association_setter, HashWithIndifferentAccess.new('foo' => HashWithIndifferentAccess.new(:id => @child_1.id, :name => 'Grace OMalley')))
|
|
369
|
+
@pirate.save
|
|
370
|
+
assert_equal 'Grace OMalley', @child_1.reload.name
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def test_should_take_a_hash_and_assign_the_attributes_to_the_associated_models
|
|
374
|
+
@pirate.attributes = @alternate_params
|
|
375
|
+
assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name
|
|
376
|
+
assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models
|
|
380
|
+
@child_1.stubs(:id).returns('ABC1X')
|
|
381
|
+
@child_2.stubs(:id).returns('ABC2X')
|
|
382
|
+
|
|
383
|
+
@pirate.attributes = {
|
|
384
|
+
association_getter => [
|
|
385
|
+
{ :id => @child_1.id, :name => 'Grace OMalley' },
|
|
386
|
+
{ :id => @child_2.id, :name => 'Privateers Greed' }
|
|
387
|
+
]
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name]
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def test_should_automatically_build_new_associated_models_for_each_entry_in_a_hash_where_the_id_is_missing
|
|
394
|
+
@pirate.send(@association_name).destroy_all
|
|
395
|
+
@pirate.reload.attributes = {
|
|
396
|
+
association_getter => { 'foo' => { :name => 'Grace OMalley' }, 'bar' => { :name => 'Privateers Greed' }}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
assert @pirate.send(@association_name).first.new_record?
|
|
400
|
+
assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name
|
|
401
|
+
|
|
402
|
+
assert @pirate.send(@association_name).last.new_record?
|
|
403
|
+
assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def test_should_not_assign_destroy_key_to_a_record
|
|
407
|
+
assert_nothing_raised ActiveRecord::UnknownAttributeError do
|
|
408
|
+
@pirate.send(association_setter, { 'foo' => { '_destroy' => '0' }})
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def test_should_ignore_new_associated_records_with_truthy_destroy_attribute
|
|
413
|
+
@pirate.send(@association_name).destroy_all
|
|
414
|
+
@pirate.reload.attributes = {
|
|
415
|
+
association_getter => {
|
|
416
|
+
'foo' => { :name => 'Grace OMalley' },
|
|
417
|
+
'bar' => { :name => 'Privateers Greed', '_destroy' => '1' }
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
assert_equal 1, @pirate.send(@association_name).length
|
|
422
|
+
assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def test_should_ignore_new_associated_records_if_a_reject_if_proc_returns_false
|
|
426
|
+
@alternate_params[association_getter]['baz'] = {}
|
|
427
|
+
assert_no_difference("@pirate.send(@association_name).length") do
|
|
428
|
+
@pirate.attributes = @alternate_params
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
def test_should_sort_the_hash_by_the_keys_before_building_new_associated_models
|
|
433
|
+
attributes = ActiveSupport::OrderedHash.new
|
|
434
|
+
attributes['123726353'] = { :name => 'Grace OMalley' }
|
|
435
|
+
attributes['2'] = { :name => 'Privateers Greed' } # 2 is lower then 123726353
|
|
436
|
+
@pirate.send(association_setter, attributes)
|
|
437
|
+
|
|
438
|
+
assert_equal ['Posideons Killer', 'Killer bandita Dionne', 'Privateers Greed', 'Grace OMalley'].to_set, @pirate.send(@association_name).map(&:name).to_set
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def test_should_raise_an_argument_error_if_something_else_than_a_hash_is_passed
|
|
442
|
+
assert_nothing_raised(ArgumentError) { @pirate.send(association_setter, {}) }
|
|
443
|
+
assert_nothing_raised(ArgumentError) { @pirate.send(association_setter, ActiveSupport::OrderedHash.new) }
|
|
444
|
+
|
|
445
|
+
assert_raise_with_message ArgumentError, 'Hash or Array expected, got String ("foo")' do
|
|
446
|
+
@pirate.send(association_setter, "foo")
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
def test_should_work_with_update_attributes_as_well
|
|
451
|
+
@pirate.update_attributes(:catchphrase => 'Arr',
|
|
452
|
+
association_getter => { 'foo' => { :id => @child_1.id, :name => 'Grace OMalley' }})
|
|
453
|
+
|
|
454
|
+
assert_equal 'Grace OMalley', @child_1.reload.name
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def test_should_update_existing_records_and_add_new_ones_that_have_no_id
|
|
458
|
+
@alternate_params[association_getter]['baz'] = { :name => 'Buccaneers Servant' }
|
|
459
|
+
assert_difference('@pirate.send(@association_name).count', +1) do
|
|
460
|
+
@pirate.update_attributes @alternate_params
|
|
461
|
+
end
|
|
462
|
+
assert_equal ['Grace OMalley', 'Privateers Greed', 'Buccaneers Servant'].to_set, @pirate.reload.send(@association_name).map(&:name).to_set
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
def test_should_be_possible_to_destroy_a_record
|
|
466
|
+
['1', 1, 'true', true].each do |true_variable|
|
|
467
|
+
record = @pirate.reload.send(@association_name).create!(:name => 'Grace OMalley')
|
|
468
|
+
@pirate.send(association_setter,
|
|
469
|
+
@alternate_params[association_getter].merge('baz' => { :id => record.id, '_destroy' => true_variable })
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
assert_difference('@pirate.send(@association_name).count', -1) do
|
|
473
|
+
@pirate.save
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def test_should_not_destroy_the_associated_model_with_a_non_truthy_argument
|
|
479
|
+
[nil, '', '0', 0, 'false', false].each do |false_variable|
|
|
480
|
+
@alternate_params[association_getter]['foo']['_destroy'] = false_variable
|
|
481
|
+
assert_no_difference('@pirate.send(@association_name).count') do
|
|
482
|
+
@pirate.update_attributes(@alternate_params)
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
|
488
|
+
assert_no_difference('@pirate.send(@association_name).count') do
|
|
489
|
+
@pirate.send(association_setter, @alternate_params[association_getter].merge('baz' => { :id => @child_1.id, '_destroy' => true }))
|
|
490
|
+
end
|
|
491
|
+
assert_difference('@pirate.send(@association_name).count', -1) { @pirate.save }
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
def test_should_automatically_enable_autosave_on_the_association
|
|
495
|
+
assert Pirate.reflect_on_association(@association_name).options[:autosave]
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
private
|
|
499
|
+
|
|
500
|
+
def association_setter
|
|
501
|
+
@association_setter ||= "#{@association_name}_attributes=".to_sym
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def association_getter
|
|
505
|
+
@association_getter ||= "#{@association_name}_attributes".to_sym
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
class TestNestedAttributesOnAHasManyAssociation < ActiveRecord::TestCase
|
|
510
|
+
def setup
|
|
511
|
+
@association_type = :has_many
|
|
512
|
+
@association_name = :birds
|
|
513
|
+
|
|
514
|
+
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
|
515
|
+
@pirate.birds.create!(:name => 'Posideons Killer')
|
|
516
|
+
@pirate.birds.create!(:name => 'Killer bandita Dionne')
|
|
517
|
+
|
|
518
|
+
@child_1, @child_2 = @pirate.birds
|
|
519
|
+
|
|
520
|
+
@alternate_params = {
|
|
521
|
+
:birds_attributes => {
|
|
522
|
+
'foo' => { :id => @child_1.id, :name => 'Grace OMalley' },
|
|
523
|
+
'bar' => { :id => @child_2.id, :name => 'Privateers Greed' }
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
include NestedAttributesOnACollectionAssociationTests
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
class TestNestedAttributesOnAHasAndBelongsToManyAssociation < ActiveRecord::TestCase
|
|
532
|
+
def setup
|
|
533
|
+
@association_type = :has_and_belongs_to_many
|
|
534
|
+
@association_name = :parrots
|
|
535
|
+
|
|
536
|
+
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
|
537
|
+
@pirate.parrots.create!(:name => 'Posideons Killer')
|
|
538
|
+
@pirate.parrots.create!(:name => 'Killer bandita Dionne')
|
|
539
|
+
|
|
540
|
+
@child_1, @child_2 = @pirate.parrots
|
|
541
|
+
|
|
542
|
+
@alternate_params = {
|
|
543
|
+
:parrots_attributes => {
|
|
544
|
+
'foo' => { :id => @child_1.id, :name => 'Grace OMalley' },
|
|
545
|
+
'bar' => { :id => @child_2.id, :name => 'Privateers Greed' }
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
include NestedAttributesOnACollectionAssociationTests
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
class TestNestedAttributesLimit < ActiveRecord::TestCase
|
|
554
|
+
def setup
|
|
555
|
+
Pirate.accepts_nested_attributes_for :parrots, :limit => 2
|
|
556
|
+
|
|
557
|
+
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def teardown
|
|
561
|
+
Pirate.accepts_nested_attributes_for :parrots, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def test_limit_with_less_records
|
|
565
|
+
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Big Big Love' } } }
|
|
566
|
+
assert_difference('Parrot.count') { @pirate.save! }
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
def test_limit_with_number_exact_records
|
|
570
|
+
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' }, 'bar' => { :name => 'Blown Away' } } }
|
|
571
|
+
assert_difference('Parrot.count', 2) { @pirate.save! }
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
def test_limit_with_exceeding_records
|
|
575
|
+
assert_raises(ActiveRecord::NestedAttributes::TooManyRecords) do
|
|
576
|
+
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' },
|
|
577
|
+
'bar' => { :name => 'Blown Away' },
|
|
578
|
+
'car' => { :name => 'The Happening' }} }
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require "cases/helper"
|
|
2
|
+
require 'models/topic'
|
|
3
|
+
require 'models/reply'
|
|
4
|
+
require 'models/subscriber'
|
|
5
|
+
require 'models/movie'
|
|
6
|
+
require 'models/keyboard'
|
|
7
|
+
require 'models/mixed_case_monkey'
|
|
8
|
+
|
|
9
|
+
class PrimaryKeysTest < ActiveRecord::TestCase
|
|
10
|
+
fixtures :topics, :subscribers, :movies, :mixed_case_monkeys
|
|
11
|
+
|
|
12
|
+
def test_integer_key
|
|
13
|
+
topic = Topic.find(1)
|
|
14
|
+
assert_equal(topics(:first).author_name, topic.author_name)
|
|
15
|
+
topic = Topic.find(2)
|
|
16
|
+
assert_equal(topics(:second).author_name, topic.author_name)
|
|
17
|
+
|
|
18
|
+
topic = Topic.new
|
|
19
|
+
topic.title = "New Topic"
|
|
20
|
+
assert_equal(nil, topic.id)
|
|
21
|
+
assert_nothing_raised { topic.save! }
|
|
22
|
+
id = topic.id
|
|
23
|
+
|
|
24
|
+
topicReloaded = Topic.find(id)
|
|
25
|
+
assert_equal("New Topic", topicReloaded.title)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_customized_primary_key_auto_assigns_on_save
|
|
29
|
+
Keyboard.delete_all
|
|
30
|
+
keyboard = Keyboard.new(:name => 'HHKB')
|
|
31
|
+
assert_nothing_raised { keyboard.save! }
|
|
32
|
+
assert_equal keyboard.id, Keyboard.find_by_name('HHKB').id
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_customized_primary_key_can_be_get_before_saving
|
|
36
|
+
keyboard = Keyboard.new
|
|
37
|
+
assert_nil keyboard.id
|
|
38
|
+
assert_nothing_raised { assert_nil keyboard.key_number }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_customized_string_primary_key_settable_before_save
|
|
42
|
+
subscriber = Subscriber.new
|
|
43
|
+
assert_nothing_raised { subscriber.id = 'webster123' }
|
|
44
|
+
assert_equal 'webster123', subscriber.id
|
|
45
|
+
assert_equal 'webster123', subscriber.nick
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_string_key
|
|
49
|
+
subscriber = Subscriber.find(subscribers(:first).nick)
|
|
50
|
+
assert_equal(subscribers(:first).name, subscriber.name)
|
|
51
|
+
subscriber = Subscriber.find(subscribers(:second).nick)
|
|
52
|
+
assert_equal(subscribers(:second).name, subscriber.name)
|
|
53
|
+
|
|
54
|
+
subscriber = Subscriber.new
|
|
55
|
+
subscriber.id = "jdoe"
|
|
56
|
+
assert_equal("jdoe", subscriber.id)
|
|
57
|
+
subscriber.name = "John Doe"
|
|
58
|
+
assert_nothing_raised { subscriber.save! }
|
|
59
|
+
assert_equal("jdoe", subscriber.id)
|
|
60
|
+
|
|
61
|
+
subscriberReloaded = Subscriber.find("jdoe")
|
|
62
|
+
assert_equal("John Doe", subscriberReloaded.name)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_find_with_more_than_one_string_key
|
|
66
|
+
assert_equal 2, Subscriber.find(subscribers(:first).nick, subscribers(:second).nick).length
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_primary_key_prefix
|
|
70
|
+
ActiveRecord::Base.primary_key_prefix_type = :table_name
|
|
71
|
+
Topic.reset_primary_key
|
|
72
|
+
assert_equal "topicid", Topic.primary_key
|
|
73
|
+
|
|
74
|
+
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
|
|
75
|
+
Topic.reset_primary_key
|
|
76
|
+
assert_equal "topic_id", Topic.primary_key
|
|
77
|
+
|
|
78
|
+
ActiveRecord::Base.primary_key_prefix_type = nil
|
|
79
|
+
Topic.reset_primary_key
|
|
80
|
+
assert_equal "id", Topic.primary_key
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_delete_should_quote_pkey
|
|
84
|
+
assert_nothing_raised { MixedCaseMonkey.delete(1) }
|
|
85
|
+
end
|
|
86
|
+
def test_update_counters_should_quote_pkey_and_quote_counter_columns
|
|
87
|
+
assert_nothing_raised { MixedCaseMonkey.update_counters(1, :fleaCount => 99) }
|
|
88
|
+
end
|
|
89
|
+
def test_find_with_one_id_should_quote_pkey
|
|
90
|
+
assert_nothing_raised { MixedCaseMonkey.find(1) }
|
|
91
|
+
end
|
|
92
|
+
def test_find_with_multiple_ids_should_quote_pkey
|
|
93
|
+
assert_nothing_raised { MixedCaseMonkey.find([1,2]) }
|
|
94
|
+
end
|
|
95
|
+
def test_instance_update_should_quote_pkey
|
|
96
|
+
assert_nothing_raised { MixedCaseMonkey.find(1).save }
|
|
97
|
+
end
|
|
98
|
+
def test_instance_destroy_should_quote_pkey
|
|
99
|
+
assert_nothing_raised { MixedCaseMonkey.find(1).destroy }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_supports_primary_key
|
|
103
|
+
assert_nothing_raised NoMethodError do
|
|
104
|
+
ActiveRecord::Base.connection.supports_primary_key?
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_primary_key_returns_value_if_it_exists
|
|
109
|
+
if ActiveRecord::Base.connection.supports_primary_key?
|
|
110
|
+
assert_equal 'id', ActiveRecord::Base.connection.primary_key('developers')
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_primary_key_returns_nil_if_it_does_not_exist
|
|
115
|
+
if ActiveRecord::Base.connection.supports_primary_key?
|
|
116
|
+
assert_nil ActiveRecord::Base.connection.primary_key('developers_projects')
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|