activerecord 2.3.18 → 3.0.0.beta
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 +105 -34
- data/examples/performance.rb +3 -39
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +81 -47
- data/lib/active_record/aggregations.rb +1 -3
- data/lib/active_record/association_preload.rb +39 -54
- data/lib/active_record/associations.rb +262 -419
- data/lib/active_record/associations/association_collection.rb +85 -100
- data/lib/active_record/associations/association_proxy.rb +20 -18
- data/lib/active_record/associations/belongs_to_association.rb +8 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -35
- data/lib/active_record/associations/has_many_association.rb +11 -19
- data/lib/active_record/associations/has_many_through_association.rb +30 -183
- data/lib/active_record/associations/has_one_association.rb +10 -10
- data/lib/active_record/associations/has_one_through_association.rb +13 -11
- data/lib/active_record/associations/through_association_scope.rb +153 -0
- data/lib/active_record/attribute_methods.rb +17 -370
- data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
- data/lib/active_record/attribute_methods/dirty.rb +87 -0
- data/lib/active_record/attribute_methods/primary_key.rb +44 -0
- data/lib/active_record/attribute_methods/query.rb +37 -0
- data/lib/active_record/attribute_methods/read.rb +116 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +60 -0
- data/lib/active_record/attribute_methods/write.rb +37 -0
- data/lib/active_record/autosave_association.rb +20 -41
- data/lib/active_record/base.rb +357 -1180
- data/lib/active_record/batches.rb +10 -16
- data/lib/active_record/callbacks.rb +66 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +17 -13
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +5 -25
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -72
- data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -49
- data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -46
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +9 -3
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +34 -65
- data/lib/active_record/fixtures.rb +21 -25
- data/lib/active_record/locale/en.yml +9 -27
- data/lib/active_record/locking/optimistic.rb +16 -48
- data/lib/active_record/migration.rb +59 -46
- data/lib/active_record/named_scope.rb +85 -92
- data/lib/active_record/nested_attributes.rb +18 -24
- data/lib/active_record/observer.rb +18 -94
- data/lib/active_record/railtie.rb +83 -0
- data/lib/active_record/railties/controller_runtime.rb +38 -0
- data/lib/active_record/railties/databases.rake +477 -0
- data/lib/active_record/railties/subscriber.rb +27 -0
- data/lib/active_record/reflection.rb +2 -15
- data/lib/active_record/relation.rb +339 -0
- data/lib/active_record/relation/calculations.rb +259 -0
- data/lib/active_record/relation/finder_methods.rb +315 -0
- data/lib/active_record/relation/predicate_builder.rb +46 -0
- data/lib/active_record/relation/query_methods.rb +218 -0
- data/lib/active_record/relation/spawn_methods.rb +102 -0
- data/lib/active_record/schema_dumper.rb +10 -6
- data/lib/active_record/serialization.rb +31 -74
- data/lib/active_record/serializers/xml_serializer.rb +33 -121
- data/lib/active_record/session_store.rb +1 -9
- data/lib/active_record/test_case.rb +1 -3
- data/lib/active_record/timestamp.rb +7 -5
- data/lib/active_record/transactions.rb +9 -9
- data/lib/active_record/validations.rb +51 -1100
- data/lib/active_record/validations/associated.rb +47 -0
- data/lib/active_record/validations/uniqueness.rb +181 -0
- data/lib/active_record/version.rb +3 -3
- data/lib/generators/active_record.rb +30 -0
- data/lib/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/generators/active_record/migration/templates/migration.rb +11 -0
- data/lib/generators/active_record/model/model_generator.rb +33 -0
- data/lib/generators/active_record/model/templates/migration.rb +16 -0
- data/lib/generators/active_record/model/templates/model.rb +5 -0
- data/lib/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/generators/active_record/session_migration/session_migration_generator.rb +24 -0
- data/lib/generators/active_record/session_migration/templates/migration.rb +16 -0
- metadata +67 -325
- data/RUNNING_UNIT_TESTS +0 -36
- data/Rakefile +0 -268
- data/install.rb +0 -30
- data/lib/active_record/calculations.rb +0 -321
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -57
- data/lib/active_record/dirty.rb +0 -183
- data/lib/active_record/serializers/json_serializer.rb +0 -91
- data/lib/activerecord.rb +0 -2
- data/test/assets/example.log +0 -1
- data/test/assets/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +0 -24
- data/test/cases/active_schema_test_mysql.rb +0 -122
- data/test/cases/active_schema_test_postgresql.rb +0 -24
- data/test/cases/adapter_test.rb +0 -144
- data/test/cases/aggregations_test.rb +0 -167
- data/test/cases/ar_schema_test.rb +0 -32
- data/test/cases/associations/belongs_to_associations_test.rb +0 -438
- data/test/cases/associations/callbacks_test.rb +0 -161
- data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
- data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
- data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
- data/test/cases/associations/eager_singularization_test.rb +0 -145
- data/test/cases/associations/eager_test.rb +0 -852
- data/test/cases/associations/extension_test.rb +0 -62
- data/test/cases/associations/habtm_join_table_test.rb +0 -56
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
- data/test/cases/associations/has_many_associations_test.rb +0 -1273
- data/test/cases/associations/has_many_through_associations_test.rb +0 -360
- data/test/cases/associations/has_one_associations_test.rb +0 -330
- data/test/cases/associations/has_one_through_associations_test.rb +0 -209
- data/test/cases/associations/inner_join_association_test.rb +0 -93
- data/test/cases/associations/inverse_associations_test.rb +0 -566
- data/test/cases/associations/join_model_test.rb +0 -712
- data/test/cases/associations_test.rb +0 -282
- data/test/cases/attribute_methods_test.rb +0 -305
- data/test/cases/autosave_association_test.rb +0 -1218
- data/test/cases/base_test.rb +0 -2166
- data/test/cases/batches_test.rb +0 -81
- data/test/cases/binary_test.rb +0 -30
- data/test/cases/calculations_test.rb +0 -360
- data/test/cases/callbacks_observers_test.rb +0 -38
- data/test/cases/callbacks_test.rb +0 -438
- data/test/cases/class_inheritable_attributes_test.rb +0 -32
- data/test/cases/column_alias_test.rb +0 -17
- data/test/cases/column_definition_test.rb +0 -70
- data/test/cases/connection_pool_test.rb +0 -25
- data/test/cases/connection_test_firebird.rb +0 -8
- data/test/cases/connection_test_mysql.rb +0 -65
- data/test/cases/copy_table_test_sqlite.rb +0 -80
- data/test/cases/counter_cache_test.rb +0 -84
- data/test/cases/database_statements_test.rb +0 -12
- data/test/cases/datatype_test_postgresql.rb +0 -204
- data/test/cases/date_time_test.rb +0 -37
- data/test/cases/default_test_firebird.rb +0 -16
- data/test/cases/defaults_test.rb +0 -111
- data/test/cases/deprecated_finder_test.rb +0 -30
- data/test/cases/dirty_test.rb +0 -316
- data/test/cases/finder_respond_to_test.rb +0 -76
- data/test/cases/finder_test.rb +0 -1098
- data/test/cases/fixtures_test.rb +0 -661
- data/test/cases/helper.rb +0 -68
- data/test/cases/i18n_test.rb +0 -46
- data/test/cases/inheritance_test.rb +0 -262
- data/test/cases/invalid_date_test.rb +0 -24
- data/test/cases/json_serialization_test.rb +0 -219
- data/test/cases/lifecycle_test.rb +0 -193
- data/test/cases/locking_test.rb +0 -350
- data/test/cases/method_scoping_test.rb +0 -704
- data/test/cases/migration_test.rb +0 -1649
- data/test/cases/migration_test_firebird.rb +0 -124
- data/test/cases/mixin_test.rb +0 -96
- data/test/cases/modules_test.rb +0 -109
- data/test/cases/multiple_db_test.rb +0 -85
- data/test/cases/named_scope_test.rb +0 -372
- data/test/cases/nested_attributes_test.rb +0 -840
- data/test/cases/pk_test.rb +0 -119
- data/test/cases/pooled_connections_test.rb +0 -103
- data/test/cases/query_cache_test.rb +0 -129
- data/test/cases/readonly_test.rb +0 -107
- data/test/cases/reflection_test.rb +0 -234
- data/test/cases/reload_models_test.rb +0 -22
- data/test/cases/repair_helper.rb +0 -50
- data/test/cases/reserved_word_test_mysql.rb +0 -176
- data/test/cases/sanitize_test.rb +0 -25
- data/test/cases/schema_authorization_test_postgresql.rb +0 -75
- data/test/cases/schema_dumper_test.rb +0 -211
- data/test/cases/schema_test_postgresql.rb +0 -178
- data/test/cases/serialization_test.rb +0 -47
- data/test/cases/sp_test_mysql.rb +0 -16
- data/test/cases/synonym_test_oracle.rb +0 -17
- data/test/cases/timestamp_test.rb +0 -75
- data/test/cases/transactions_test.rb +0 -543
- data/test/cases/unconnected_test.rb +0 -32
- data/test/cases/validations_i18n_test.rb +0 -925
- data/test/cases/validations_test.rb +0 -1684
- data/test/cases/xml_serialization_test.rb +0 -240
- data/test/cases/yaml_serialization_test.rb +0 -11
- data/test/config.rb +0 -5
- data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
- data/test/connections/jdbc_jdbch2/connection.rb +0 -18
- data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
- data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
- data/test/connections/native_db2/connection.rb +0 -25
- data/test/connections/native_firebird/connection.rb +0 -26
- data/test/connections/native_frontbase/connection.rb +0 -27
- data/test/connections/native_mysql/connection.rb +0 -25
- data/test/connections/native_openbase/connection.rb +0 -21
- data/test/connections/native_oracle/connection.rb +0 -27
- data/test/connections/native_postgresql/connection.rb +0 -21
- data/test/connections/native_sqlite/connection.rb +0 -25
- data/test/connections/native_sqlite3/connection.rb +0 -25
- data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
- data/test/connections/native_sybase/connection.rb +0 -23
- data/test/fixtures/accounts.yml +0 -29
- 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 +0 -5
- data/test/fixtures/author_favorites.yml +0 -4
- data/test/fixtures/authors.yml +0 -9
- data/test/fixtures/binaries.yml +0 -132
- data/test/fixtures/books.yml +0 -7
- data/test/fixtures/categories.yml +0 -14
- data/test/fixtures/categories/special_categories.yml +0 -9
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
- data/test/fixtures/categories_ordered.yml +0 -7
- data/test/fixtures/categories_posts.yml +0 -23
- data/test/fixtures/categorizations.yml +0 -17
- data/test/fixtures/clubs.yml +0 -6
- data/test/fixtures/comments.yml +0 -59
- data/test/fixtures/companies.yml +0 -56
- data/test/fixtures/computers.yml +0 -4
- data/test/fixtures/courses.yml +0 -7
- data/test/fixtures/customers.yml +0 -26
- data/test/fixtures/developers.yml +0 -21
- data/test/fixtures/developers_projects.yml +0 -17
- data/test/fixtures/edges.yml +0 -6
- data/test/fixtures/entrants.yml +0 -14
- data/test/fixtures/faces.yml +0 -11
- data/test/fixtures/fk_test_has_fk.yml +0 -3
- data/test/fixtures/fk_test_has_pk.yml +0 -2
- data/test/fixtures/funny_jokes.yml +0 -10
- data/test/fixtures/interests.yml +0 -33
- data/test/fixtures/items.yml +0 -4
- data/test/fixtures/jobs.yml +0 -7
- data/test/fixtures/legacy_things.yml +0 -3
- data/test/fixtures/mateys.yml +0 -4
- data/test/fixtures/member_types.yml +0 -6
- data/test/fixtures/members.yml +0 -6
- data/test/fixtures/memberships.yml +0 -20
- data/test/fixtures/men.yml +0 -5
- data/test/fixtures/minimalistics.yml +0 -2
- data/test/fixtures/mixed_case_monkeys.yml +0 -6
- data/test/fixtures/mixins.yml +0 -29
- data/test/fixtures/movies.yml +0 -7
- data/test/fixtures/naked/csv/accounts.csv +0 -1
- data/test/fixtures/naked/yml/accounts.yml +0 -1
- data/test/fixtures/naked/yml/companies.yml +0 -1
- data/test/fixtures/naked/yml/courses.yml +0 -1
- data/test/fixtures/organizations.yml +0 -5
- data/test/fixtures/owners.yml +0 -7
- data/test/fixtures/parrots.yml +0 -27
- data/test/fixtures/parrots_pirates.yml +0 -7
- data/test/fixtures/people.yml +0 -15
- data/test/fixtures/pets.yml +0 -14
- data/test/fixtures/pirates.yml +0 -9
- data/test/fixtures/polymorphic_designs.yml +0 -19
- data/test/fixtures/polymorphic_prices.yml +0 -19
- data/test/fixtures/posts.yml +0 -52
- data/test/fixtures/price_estimates.yml +0 -7
- data/test/fixtures/projects.yml +0 -7
- data/test/fixtures/readers.yml +0 -9
- data/test/fixtures/references.yml +0 -17
- data/test/fixtures/reserved_words/distinct.yml +0 -5
- data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
- data/test/fixtures/reserved_words/group.yml +0 -14
- data/test/fixtures/reserved_words/select.yml +0 -8
- data/test/fixtures/reserved_words/values.yml +0 -7
- data/test/fixtures/ships.yml +0 -5
- data/test/fixtures/sponsors.yml +0 -9
- data/test/fixtures/subscribers.yml +0 -7
- data/test/fixtures/subscriptions.yml +0 -12
- data/test/fixtures/taggings.yml +0 -28
- data/test/fixtures/tags.yml +0 -7
- data/test/fixtures/tasks.yml +0 -7
- data/test/fixtures/tees.yml +0 -4
- data/test/fixtures/ties.yml +0 -4
- data/test/fixtures/topics.yml +0 -42
- data/test/fixtures/toys.yml +0 -4
- data/test/fixtures/treasures.yml +0 -10
- data/test/fixtures/vertices.yml +0 -4
- data/test/fixtures/warehouse-things.yml +0 -3
- data/test/fixtures/zines.yml +0 -5
- data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
- data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
- data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
- data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
- data/test/migrations/duplicate/3_foo.rb +0 -7
- data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
- data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
- data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
- data/test/migrations/missing/1_people_have_last_names.rb +0 -9
- data/test/migrations/missing/3_we_need_reminders.rb +0 -12
- data/test/migrations/missing/4_innocent_jointable.rb +0 -12
- data/test/migrations/valid/1_people_have_last_names.rb +0 -9
- data/test/migrations/valid/2_we_need_reminders.rb +0 -12
- data/test/migrations/valid/3_innocent_jointable.rb +0 -12
- data/test/models/author.rb +0 -151
- data/test/models/auto_id.rb +0 -4
- data/test/models/binary.rb +0 -2
- data/test/models/bird.rb +0 -9
- data/test/models/book.rb +0 -4
- data/test/models/categorization.rb +0 -5
- data/test/models/category.rb +0 -34
- data/test/models/citation.rb +0 -6
- data/test/models/club.rb +0 -13
- data/test/models/column_name.rb +0 -3
- data/test/models/comment.rb +0 -29
- data/test/models/company.rb +0 -173
- data/test/models/company_in_module.rb +0 -78
- data/test/models/computer.rb +0 -3
- data/test/models/contact.rb +0 -16
- data/test/models/contract.rb +0 -5
- data/test/models/course.rb +0 -3
- data/test/models/customer.rb +0 -73
- data/test/models/default.rb +0 -2
- data/test/models/developer.rb +0 -101
- data/test/models/edge.rb +0 -5
- data/test/models/entrant.rb +0 -3
- data/test/models/essay.rb +0 -3
- data/test/models/event.rb +0 -3
- data/test/models/event_author.rb +0 -8
- data/test/models/face.rb +0 -7
- data/test/models/guid.rb +0 -2
- data/test/models/interest.rb +0 -5
- data/test/models/invoice.rb +0 -4
- data/test/models/item.rb +0 -7
- data/test/models/job.rb +0 -5
- data/test/models/joke.rb +0 -3
- data/test/models/keyboard.rb +0 -3
- data/test/models/legacy_thing.rb +0 -3
- data/test/models/line_item.rb +0 -3
- data/test/models/man.rb +0 -9
- data/test/models/matey.rb +0 -4
- data/test/models/member.rb +0 -12
- data/test/models/member_detail.rb +0 -5
- data/test/models/member_type.rb +0 -3
- data/test/models/membership.rb +0 -9
- data/test/models/minimalistic.rb +0 -2
- data/test/models/mixed_case_monkey.rb +0 -3
- data/test/models/movie.rb +0 -5
- data/test/models/order.rb +0 -4
- data/test/models/organization.rb +0 -6
- data/test/models/owner.rb +0 -5
- data/test/models/parrot.rb +0 -22
- data/test/models/person.rb +0 -16
- data/test/models/pet.rb +0 -5
- data/test/models/pirate.rb +0 -80
- data/test/models/polymorphic_design.rb +0 -3
- data/test/models/polymorphic_price.rb +0 -3
- data/test/models/post.rb +0 -102
- data/test/models/price_estimate.rb +0 -3
- data/test/models/project.rb +0 -30
- data/test/models/reader.rb +0 -4
- data/test/models/reference.rb +0 -4
- data/test/models/reply.rb +0 -46
- data/test/models/ship.rb +0 -19
- data/test/models/ship_part.rb +0 -7
- data/test/models/sponsor.rb +0 -4
- data/test/models/subject.rb +0 -4
- data/test/models/subscriber.rb +0 -8
- data/test/models/subscription.rb +0 -4
- data/test/models/tag.rb +0 -7
- data/test/models/tagging.rb +0 -10
- data/test/models/task.rb +0 -3
- data/test/models/tee.rb +0 -4
- data/test/models/tie.rb +0 -4
- data/test/models/topic.rb +0 -80
- data/test/models/toy.rb +0 -6
- data/test/models/treasure.rb +0 -8
- data/test/models/vertex.rb +0 -9
- data/test/models/warehouse_thing.rb +0 -5
- data/test/models/zine.rb +0 -3
- data/test/schema/mysql_specific_schema.rb +0 -31
- data/test/schema/postgresql_specific_schema.rb +0 -114
- data/test/schema/schema.rb +0 -550
- data/test/schema/schema2.rb +0 -6
- data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -1,840 +0,0 @@
|
|
1
|
-
require "cases/helper"
|
2
|
-
require "models/pirate"
|
3
|
-
require "models/ship"
|
4
|
-
require "models/ship_part"
|
5
|
-
require "models/bird"
|
6
|
-
require "models/parrot"
|
7
|
-
require "models/treasure"
|
8
|
-
require "models/man"
|
9
|
-
require "models/interest"
|
10
|
-
require "models/owner"
|
11
|
-
require "models/pet"
|
12
|
-
|
13
|
-
module AssertRaiseWithMessage
|
14
|
-
def assert_raise_with_message(expected_exception, expected_message)
|
15
|
-
begin
|
16
|
-
error_raised = false
|
17
|
-
yield
|
18
|
-
rescue expected_exception => error
|
19
|
-
error_raised = true
|
20
|
-
actual_message = error.message
|
21
|
-
end
|
22
|
-
assert error_raised
|
23
|
-
assert_equal expected_message, actual_message
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class TestNestedAttributesInGeneral < ActiveRecord::TestCase
|
28
|
-
include AssertRaiseWithMessage
|
29
|
-
|
30
|
-
def teardown
|
31
|
-
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_base_should_have_an_empty_nested_attributes_options
|
35
|
-
assert_equal Hash.new, ActiveRecord::Base.nested_attributes_options
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_should_add_a_proc_to_nested_attributes_options
|
39
|
-
assert_equal ActiveRecord::NestedAttributes::ClassMethods::REJECT_ALL_BLANK_PROC,
|
40
|
-
Pirate.nested_attributes_options[:birds_with_reject_all_blank][:reject_if]
|
41
|
-
|
42
|
-
[:parrots, :birds].each do |name|
|
43
|
-
assert_instance_of Proc, Pirate.nested_attributes_options[name][:reject_if]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_should_not_build_a_new_record_if_reject_all_blank_returns_false
|
48
|
-
pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
49
|
-
pirate.birds_with_reject_all_blank_attributes = [{:name => '', :color => ''}]
|
50
|
-
pirate.save!
|
51
|
-
|
52
|
-
assert pirate.birds_with_reject_all_blank.empty?
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_should_build_a_new_record_if_reject_all_blank_does_not_return_false
|
56
|
-
pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
57
|
-
pirate.birds_with_reject_all_blank_attributes = [{:name => 'Tweetie', :color => ''}]
|
58
|
-
pirate.save!
|
59
|
-
|
60
|
-
assert_equal 1, pirate.birds_with_reject_all_blank.count
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_should_raise_an_ArgumentError_for_non_existing_associations
|
64
|
-
assert_raise_with_message ArgumentError, "No association found for name `honesty'. Has it been defined yet?" do
|
65
|
-
Pirate.accepts_nested_attributes_for :honesty
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def test_should_disable_allow_destroy_by_default
|
70
|
-
Pirate.accepts_nested_attributes_for :ship
|
71
|
-
|
72
|
-
pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
73
|
-
ship = pirate.create_ship(:name => 'Nights Dirty Lightning')
|
74
|
-
|
75
|
-
assert_no_difference('Ship.count') do
|
76
|
-
pirate.update_attributes(:ship_attributes => { '_destroy' => true })
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_a_model_should_respond_to_underscore_destroy_and_return_if_it_is_marked_for_destruction
|
81
|
-
ship = Ship.create!(:name => 'Nights Dirty Lightning')
|
82
|
-
assert !ship._destroy
|
83
|
-
ship.mark_for_destruction
|
84
|
-
assert ship._destroy
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_reject_if_method_without_arguments
|
88
|
-
Pirate.accepts_nested_attributes_for :ship, :reject_if => :new_record?
|
89
|
-
|
90
|
-
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
91
|
-
pirate.ship_attributes = { :name => 'Black Pearl' }
|
92
|
-
assert_no_difference('Ship.count') { pirate.save! }
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_reject_if_method_with_arguments
|
96
|
-
Pirate.accepts_nested_attributes_for :ship, :reject_if => :reject_empty_ships_on_create
|
97
|
-
|
98
|
-
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
99
|
-
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
100
|
-
assert_no_difference('Ship.count') { pirate.save! }
|
101
|
-
|
102
|
-
# pirate.reject_empty_ships_on_create returns false for saved records
|
103
|
-
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
|
104
|
-
assert_difference('Ship.count') { pirate.save! }
|
105
|
-
end
|
106
|
-
|
107
|
-
def test_reject_if_with_indifferent_keys
|
108
|
-
Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:name].blank? }
|
109
|
-
|
110
|
-
pirate = Pirate.new(:catchphrase => "Stop wastin' me time")
|
111
|
-
pirate.ship_attributes = { :name => 'Hello Pearl' }
|
112
|
-
assert_difference('Ship.count') { pirate.save! }
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
|
117
|
-
include AssertRaiseWithMessage
|
118
|
-
|
119
|
-
def setup
|
120
|
-
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
121
|
-
@ship = @pirate.create_ship(:name => 'Nights Dirty Lightning')
|
122
|
-
end
|
123
|
-
|
124
|
-
def test_should_raise_argument_error_if_trying_to_build_polymorphic_belongs_to
|
125
|
-
assert_raise_with_message ArgumentError, "Cannot build association looter. Are you trying to build a polymorphic one-to-one association?" do
|
126
|
-
Treasure.new(:name => 'pearl', :looter_attributes => {:catchphrase => "Arrr"})
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def test_should_define_an_attribute_writer_method_for_the_association
|
131
|
-
assert_respond_to @pirate, :ship_attributes=
|
132
|
-
end
|
133
|
-
|
134
|
-
def test_should_build_a_new_record_if_there_is_no_id
|
135
|
-
@ship.destroy
|
136
|
-
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' }
|
137
|
-
|
138
|
-
assert @pirate.ship.new_record?
|
139
|
-
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy
|
143
|
-
@ship.destroy
|
144
|
-
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' }
|
145
|
-
|
146
|
-
assert_nil @pirate.ship
|
147
|
-
end
|
148
|
-
|
149
|
-
def test_should_not_build_a_new_record_if_a_reject_if_proc_returns_false
|
150
|
-
@ship.destroy
|
151
|
-
@pirate.reload.ship_attributes = {}
|
152
|
-
|
153
|
-
assert_nil @pirate.ship
|
154
|
-
end
|
155
|
-
|
156
|
-
def test_should_replace_an_existing_record_if_there_is_no_id
|
157
|
-
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' }
|
158
|
-
|
159
|
-
assert @pirate.ship.new_record?
|
160
|
-
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
161
|
-
assert_equal 'Nights Dirty Lightning', @ship.name
|
162
|
-
end
|
163
|
-
|
164
|
-
def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy
|
165
|
-
@pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' }
|
166
|
-
|
167
|
-
assert_equal @ship, @pirate.ship
|
168
|
-
assert_equal 'Nights Dirty Lightning', @pirate.ship.name
|
169
|
-
end
|
170
|
-
|
171
|
-
def test_should_modify_an_existing_record_if_there_is_a_matching_id
|
172
|
-
@pirate.reload.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' }
|
173
|
-
|
174
|
-
assert_equal @ship, @pirate.ship
|
175
|
-
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
176
|
-
end
|
177
|
-
|
178
|
-
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
179
|
-
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Ship with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
|
180
|
-
@pirate.ship_attributes = { :id => 1234567890 }
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
185
|
-
@pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' }
|
186
|
-
|
187
|
-
assert_equal @ship, @pirate.ship
|
188
|
-
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
189
|
-
end
|
190
|
-
|
191
|
-
def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id
|
192
|
-
@ship.stubs(:id).returns('ABC1X')
|
193
|
-
@pirate.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' }
|
194
|
-
|
195
|
-
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
196
|
-
end
|
197
|
-
|
198
|
-
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
|
199
|
-
@pirate.ship.destroy
|
200
|
-
[1, '1', true, 'true'].each do |truth|
|
201
|
-
@pirate.reload.create_ship(:name => 'Mister Pablo')
|
202
|
-
assert_difference('Ship.count', -1) do
|
203
|
-
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => truth })
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
|
209
|
-
[nil, '0', 0, 'false', false].each do |not_truth|
|
210
|
-
assert_no_difference('Ship.count') do
|
211
|
-
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => not_truth })
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
|
217
|
-
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
|
218
|
-
|
219
|
-
assert_no_difference('Ship.count') do
|
220
|
-
@pirate.update_attribute(:ship_attributes, { :id => @pirate.ship.id, :_destroy => '1' })
|
221
|
-
end
|
222
|
-
|
223
|
-
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
224
|
-
end
|
225
|
-
|
226
|
-
def test_should_also_work_with_a_HashWithIndifferentAccess
|
227
|
-
@pirate.ship_attributes = HashWithIndifferentAccess.new(:id => @ship.id, :name => 'Davy Jones Gold Dagger')
|
228
|
-
|
229
|
-
assert !@pirate.ship.new_record?
|
230
|
-
assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name
|
231
|
-
end
|
232
|
-
|
233
|
-
def test_should_work_with_update_attributes_as_well
|
234
|
-
@pirate.update_attributes({ :catchphrase => 'Arr', :ship_attributes => { :id => @ship.id, :name => 'Mister Pablo' } })
|
235
|
-
@pirate.reload
|
236
|
-
|
237
|
-
assert_equal 'Arr', @pirate.catchphrase
|
238
|
-
assert_equal 'Mister Pablo', @pirate.ship.name
|
239
|
-
end
|
240
|
-
|
241
|
-
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
242
|
-
assert_no_difference('Ship.count') do
|
243
|
-
@pirate.attributes = { :ship_attributes => { :id => @ship.id, :_destroy => '1' } }
|
244
|
-
end
|
245
|
-
assert_difference('Ship.count', -1) do
|
246
|
-
@pirate.save
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
def test_should_automatically_enable_autosave_on_the_association
|
251
|
-
assert Pirate.reflect_on_association(:ship).options[:autosave]
|
252
|
-
end
|
253
|
-
|
254
|
-
def test_should_accept_update_only_option
|
255
|
-
@pirate.update_attribute(:update_only_ship_attributes, { :id => @pirate.ship.id, :name => 'Mayflower' })
|
256
|
-
end
|
257
|
-
|
258
|
-
def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true
|
259
|
-
@ship.delete
|
260
|
-
assert_difference('Ship.count', 1) do
|
261
|
-
@pirate.reload.update_attribute(:update_only_ship_attributes, { :name => 'Mayflower' })
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
|
266
|
-
@ship.delete
|
267
|
-
@ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
|
268
|
-
|
269
|
-
assert_no_difference('Ship.count') do
|
270
|
-
@pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower' })
|
271
|
-
end
|
272
|
-
assert_equal 'Mayflower', @ship.reload.name
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
|
277
|
-
include AssertRaiseWithMessage
|
278
|
-
|
279
|
-
def setup
|
280
|
-
@ship = Ship.new(:name => 'Nights Dirty Lightning')
|
281
|
-
@pirate = @ship.build_pirate(:catchphrase => 'Aye')
|
282
|
-
@ship.save!
|
283
|
-
end
|
284
|
-
|
285
|
-
def test_should_define_an_attribute_writer_method_for_the_association
|
286
|
-
assert_respond_to @ship, :pirate_attributes=
|
287
|
-
end
|
288
|
-
|
289
|
-
def test_should_build_a_new_record_if_there_is_no_id
|
290
|
-
@pirate.destroy
|
291
|
-
@ship.reload.pirate_attributes = { :catchphrase => 'Arr' }
|
292
|
-
|
293
|
-
assert @ship.pirate.new_record?
|
294
|
-
assert_equal 'Arr', @ship.pirate.catchphrase
|
295
|
-
end
|
296
|
-
|
297
|
-
def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy
|
298
|
-
@pirate.destroy
|
299
|
-
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' }
|
300
|
-
|
301
|
-
assert_nil @ship.pirate
|
302
|
-
end
|
303
|
-
|
304
|
-
def test_should_not_build_a_new_record_if_a_reject_if_proc_returns_false
|
305
|
-
@pirate.destroy
|
306
|
-
@ship.reload.pirate_attributes = {}
|
307
|
-
|
308
|
-
assert_nil @ship.pirate
|
309
|
-
end
|
310
|
-
|
311
|
-
def test_should_replace_an_existing_record_if_there_is_no_id
|
312
|
-
@ship.reload.pirate_attributes = { :catchphrase => 'Arr' }
|
313
|
-
|
314
|
-
assert @ship.pirate.new_record?
|
315
|
-
assert_equal 'Arr', @ship.pirate.catchphrase
|
316
|
-
assert_equal 'Aye', @pirate.catchphrase
|
317
|
-
end
|
318
|
-
|
319
|
-
def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy
|
320
|
-
@ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' }
|
321
|
-
|
322
|
-
assert_equal @pirate, @ship.pirate
|
323
|
-
assert_equal 'Aye', @ship.pirate.catchphrase
|
324
|
-
end
|
325
|
-
|
326
|
-
def test_should_modify_an_existing_record_if_there_is_a_matching_id
|
327
|
-
@ship.reload.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' }
|
328
|
-
|
329
|
-
assert_equal @pirate, @ship.pirate
|
330
|
-
assert_equal 'Arr', @ship.pirate.catchphrase
|
331
|
-
end
|
332
|
-
|
333
|
-
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
334
|
-
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find Pirate with ID=1234567890 for Ship with ID=#{@ship.id}" do
|
335
|
-
@ship.pirate_attributes = { :id => 1234567890 }
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
def test_should_take_a_hash_with_string_keys_and_update_the_associated_model
|
340
|
-
@ship.reload.pirate_attributes = { 'id' => @pirate.id, 'catchphrase' => 'Arr' }
|
341
|
-
|
342
|
-
assert_equal @pirate, @ship.pirate
|
343
|
-
assert_equal 'Arr', @ship.pirate.catchphrase
|
344
|
-
end
|
345
|
-
|
346
|
-
def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id
|
347
|
-
@pirate.stubs(:id).returns('ABC1X')
|
348
|
-
@ship.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' }
|
349
|
-
|
350
|
-
assert_equal 'Arr', @ship.pirate.catchphrase
|
351
|
-
end
|
352
|
-
|
353
|
-
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
|
354
|
-
@ship.pirate.destroy
|
355
|
-
[1, '1', true, 'true'].each do |truth|
|
356
|
-
@ship.reload.create_pirate(:catchphrase => 'Arr')
|
357
|
-
assert_difference('Pirate.count', -1) do
|
358
|
-
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => truth })
|
359
|
-
end
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
|
364
|
-
[nil, '0', 0, 'false', false].each do |not_truth|
|
365
|
-
assert_no_difference('Pirate.count') do
|
366
|
-
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => not_truth })
|
367
|
-
end
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
|
372
|
-
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
|
373
|
-
|
374
|
-
assert_no_difference('Pirate.count') do
|
375
|
-
@ship.update_attribute(:pirate_attributes, { :id => @ship.pirate.id, :_destroy => '1' })
|
376
|
-
end
|
377
|
-
|
378
|
-
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
379
|
-
end
|
380
|
-
|
381
|
-
def test_should_work_with_update_attributes_as_well
|
382
|
-
@ship.update_attributes({ :name => 'Mister Pablo', :pirate_attributes => { :catchphrase => 'Arr' } })
|
383
|
-
@ship.reload
|
384
|
-
|
385
|
-
assert_equal 'Mister Pablo', @ship.name
|
386
|
-
assert_equal 'Arr', @ship.pirate.catchphrase
|
387
|
-
end
|
388
|
-
|
389
|
-
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
390
|
-
assert_no_difference('Pirate.count') do
|
391
|
-
@ship.attributes = { :pirate_attributes => { :id => @ship.pirate.id, '_destroy' => true } }
|
392
|
-
end
|
393
|
-
assert_difference('Pirate.count', -1) { @ship.save }
|
394
|
-
end
|
395
|
-
|
396
|
-
def test_should_automatically_enable_autosave_on_the_association
|
397
|
-
assert Ship.reflect_on_association(:pirate).options[:autosave]
|
398
|
-
end
|
399
|
-
|
400
|
-
def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true
|
401
|
-
@pirate.delete
|
402
|
-
assert_difference('Pirate.count', 1) do
|
403
|
-
@ship.reload.update_attribute(:update_only_pirate_attributes, { :catchphrase => 'Arr' })
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
|
408
|
-
@pirate.delete
|
409
|
-
@pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
|
410
|
-
|
411
|
-
assert_no_difference('Pirate.count') do
|
412
|
-
@ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr' })
|
413
|
-
end
|
414
|
-
assert_equal 'Arr', @pirate.reload.catchphrase
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
module NestedAttributesOnACollectionAssociationTests
|
419
|
-
include AssertRaiseWithMessage
|
420
|
-
|
421
|
-
def test_should_define_an_attribute_writer_method_for_the_association
|
422
|
-
assert_respond_to @pirate, association_setter
|
423
|
-
end
|
424
|
-
|
425
|
-
def test_should_save_only_one_association_on_create
|
426
|
-
pirate = Pirate.create!({
|
427
|
-
:catchphrase => 'Arr',
|
428
|
-
association_getter => { 'foo' => { :name => 'Grace OMalley' } }
|
429
|
-
})
|
430
|
-
|
431
|
-
assert_equal 1, pirate.reload.send(@association_name).count
|
432
|
-
end
|
433
|
-
|
434
|
-
def test_should_take_a_hash_with_string_keys_and_assign_the_attributes_to_the_associated_models
|
435
|
-
@alternate_params[association_getter].stringify_keys!
|
436
|
-
@pirate.update_attributes @alternate_params
|
437
|
-
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
|
438
|
-
end
|
439
|
-
|
440
|
-
def test_should_take_an_array_and_assign_the_attributes_to_the_associated_models
|
441
|
-
@pirate.send(association_setter, @alternate_params[association_getter].values)
|
442
|
-
@pirate.save
|
443
|
-
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name]
|
444
|
-
end
|
445
|
-
|
446
|
-
def test_should_also_work_with_a_HashWithIndifferentAccess
|
447
|
-
@pirate.send(association_setter, HashWithIndifferentAccess.new('foo' => HashWithIndifferentAccess.new(:id => @child_1.id, :name => 'Grace OMalley')))
|
448
|
-
@pirate.save
|
449
|
-
assert_equal 'Grace OMalley', @child_1.reload.name
|
450
|
-
end
|
451
|
-
|
452
|
-
def test_should_take_a_hash_and_assign_the_attributes_to_the_associated_models
|
453
|
-
@pirate.attributes = @alternate_params
|
454
|
-
assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name
|
455
|
-
assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name
|
456
|
-
end
|
457
|
-
|
458
|
-
def test_should_not_load_association_when_updating_existing_records
|
459
|
-
@pirate.reload
|
460
|
-
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
|
461
|
-
assert ! @pirate.send(@association_name).loaded?
|
462
|
-
|
463
|
-
@pirate.save
|
464
|
-
assert ! @pirate.send(@association_name).loaded?
|
465
|
-
assert_equal 'Grace OMalley', @child_1.reload.name
|
466
|
-
end
|
467
|
-
|
468
|
-
def test_should_not_overwrite_unsaved_updates_when_loading_association
|
469
|
-
@pirate.reload
|
470
|
-
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
|
471
|
-
assert_equal 'Grace OMalley', @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.name
|
472
|
-
end
|
473
|
-
|
474
|
-
def test_should_preserve_order_when_not_overwriting_unsaved_updates
|
475
|
-
@pirate.reload
|
476
|
-
@pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }])
|
477
|
-
assert_equal @child_1.id, @pirate.send(@association_name).send(:load_target).first.id
|
478
|
-
end
|
479
|
-
|
480
|
-
def test_should_refresh_saved_records_when_not_overwriting_unsaved_updates
|
481
|
-
@pirate.reload
|
482
|
-
record = @pirate.class.reflect_on_association(@association_name).klass.new(:name => 'Grace OMalley')
|
483
|
-
@pirate.send(@association_name) << record
|
484
|
-
record.save!
|
485
|
-
@pirate.send(@association_name).last.update_attributes!(:name => 'Polly')
|
486
|
-
assert_equal 'Polly', @pirate.send(@association_name).send(:load_target).last.name
|
487
|
-
end
|
488
|
-
|
489
|
-
def test_should_not_remove_scheduled_destroys_when_loading_association
|
490
|
-
@pirate.reload
|
491
|
-
@pirate.send(association_setter, [{ :id => @child_1.id, :_destroy => '1' }])
|
492
|
-
assert @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.marked_for_destruction?
|
493
|
-
end
|
494
|
-
|
495
|
-
def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models
|
496
|
-
@child_1.stubs(:id).returns('ABC1X')
|
497
|
-
@child_2.stubs(:id).returns('ABC2X')
|
498
|
-
|
499
|
-
@pirate.attributes = {
|
500
|
-
association_getter => [
|
501
|
-
{ :id => @child_1.id, :name => 'Grace OMalley' },
|
502
|
-
{ :id => @child_2.id, :name => 'Privateers Greed' }
|
503
|
-
]
|
504
|
-
}
|
505
|
-
|
506
|
-
assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name]
|
507
|
-
end
|
508
|
-
|
509
|
-
def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record
|
510
|
-
assert_raise_with_message ActiveRecord::RecordNotFound, "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}" do
|
511
|
-
@pirate.attributes = { association_getter => [{ :id => 1234567890 }] }
|
512
|
-
end
|
513
|
-
end
|
514
|
-
|
515
|
-
def test_should_automatically_build_new_associated_models_for_each_entry_in_a_hash_where_the_id_is_missing
|
516
|
-
@pirate.send(@association_name).destroy_all
|
517
|
-
@pirate.reload.attributes = {
|
518
|
-
association_getter => { 'foo' => { :name => 'Grace OMalley' }, 'bar' => { :name => 'Privateers Greed' }}
|
519
|
-
}
|
520
|
-
|
521
|
-
assert @pirate.send(@association_name).first.new_record?
|
522
|
-
assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name
|
523
|
-
|
524
|
-
assert @pirate.send(@association_name).last.new_record?
|
525
|
-
assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name
|
526
|
-
end
|
527
|
-
|
528
|
-
def test_should_not_assign_destroy_key_to_a_record
|
529
|
-
assert_nothing_raised ActiveRecord::UnknownAttributeError do
|
530
|
-
@pirate.send(association_setter, { 'foo' => { '_destroy' => '0' }})
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
def test_should_ignore_new_associated_records_with_truthy_destroy_attribute
|
535
|
-
@pirate.send(@association_name).destroy_all
|
536
|
-
@pirate.reload.attributes = {
|
537
|
-
association_getter => {
|
538
|
-
'foo' => { :name => 'Grace OMalley' },
|
539
|
-
'bar' => { :name => 'Privateers Greed', '_destroy' => '1' }
|
540
|
-
}
|
541
|
-
}
|
542
|
-
|
543
|
-
assert_equal 1, @pirate.send(@association_name).length
|
544
|
-
assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name
|
545
|
-
end
|
546
|
-
|
547
|
-
def test_should_ignore_new_associated_records_if_a_reject_if_proc_returns_false
|
548
|
-
@alternate_params[association_getter]['baz'] = {}
|
549
|
-
assert_no_difference("@pirate.send(@association_name).count") do
|
550
|
-
@pirate.attributes = @alternate_params
|
551
|
-
end
|
552
|
-
end
|
553
|
-
|
554
|
-
def test_should_sort_the_hash_by_the_keys_before_building_new_associated_models
|
555
|
-
attributes = ActiveSupport::OrderedHash.new
|
556
|
-
attributes['123726353'] = { :name => 'Grace OMalley' }
|
557
|
-
attributes['2'] = { :name => 'Privateers Greed' } # 2 is lower then 123726353
|
558
|
-
@pirate.send(association_setter, attributes)
|
559
|
-
|
560
|
-
assert_equal ['Posideons Killer', 'Killer bandita Dionne', 'Privateers Greed', 'Grace OMalley'].to_set, @pirate.send(@association_name).map(&:name).to_set
|
561
|
-
end
|
562
|
-
|
563
|
-
def test_should_raise_an_argument_error_if_something_else_than_a_hash_is_passed
|
564
|
-
assert_nothing_raised(ArgumentError) { @pirate.send(association_setter, {}) }
|
565
|
-
assert_nothing_raised(ArgumentError) { @pirate.send(association_setter, ActiveSupport::OrderedHash.new) }
|
566
|
-
|
567
|
-
assert_raise_with_message ArgumentError, 'Hash or Array expected, got String ("foo")' do
|
568
|
-
@pirate.send(association_setter, "foo")
|
569
|
-
end
|
570
|
-
end
|
571
|
-
|
572
|
-
def test_should_work_with_update_attributes_as_well
|
573
|
-
@pirate.update_attributes(:catchphrase => 'Arr',
|
574
|
-
association_getter => { 'foo' => { :id => @child_1.id, :name => 'Grace OMalley' }})
|
575
|
-
|
576
|
-
assert_equal 'Grace OMalley', @child_1.reload.name
|
577
|
-
end
|
578
|
-
|
579
|
-
def test_should_update_existing_records_and_add_new_ones_that_have_no_id
|
580
|
-
@alternate_params[association_getter]['baz'] = { :name => 'Buccaneers Servant' }
|
581
|
-
assert_difference('@pirate.send(@association_name).count', +1) do
|
582
|
-
@pirate.update_attributes @alternate_params
|
583
|
-
end
|
584
|
-
assert_equal ['Grace OMalley', 'Privateers Greed', 'Buccaneers Servant'].to_set, @pirate.reload.send(@association_name).map(&:name).to_set
|
585
|
-
end
|
586
|
-
|
587
|
-
def test_should_be_possible_to_destroy_a_record
|
588
|
-
['1', 1, 'true', true].each do |true_variable|
|
589
|
-
record = @pirate.reload.send(@association_name).create!(:name => 'Grace OMalley')
|
590
|
-
@pirate.send(association_setter,
|
591
|
-
@alternate_params[association_getter].merge('baz' => { :id => record.id, '_destroy' => true_variable })
|
592
|
-
)
|
593
|
-
|
594
|
-
assert_difference('@pirate.send(@association_name).count', -1) do
|
595
|
-
@pirate.save
|
596
|
-
end
|
597
|
-
end
|
598
|
-
end
|
599
|
-
|
600
|
-
def test_should_not_destroy_the_associated_model_with_a_non_truthy_argument
|
601
|
-
[nil, '', '0', 0, 'false', false].each do |false_variable|
|
602
|
-
@alternate_params[association_getter]['foo']['_destroy'] = false_variable
|
603
|
-
assert_no_difference('@pirate.send(@association_name).count') do
|
604
|
-
@pirate.update_attributes(@alternate_params)
|
605
|
-
end
|
606
|
-
end
|
607
|
-
end
|
608
|
-
|
609
|
-
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
|
610
|
-
assert_no_difference('@pirate.send(@association_name).count') do
|
611
|
-
@pirate.send(association_setter, @alternate_params[association_getter].merge('baz' => { :id => @child_1.id, '_destroy' => true }))
|
612
|
-
end
|
613
|
-
assert_difference('@pirate.send(@association_name).count', -1) { @pirate.save }
|
614
|
-
end
|
615
|
-
|
616
|
-
def test_should_automatically_enable_autosave_on_the_association
|
617
|
-
assert Pirate.reflect_on_association(@association_name).options[:autosave]
|
618
|
-
end
|
619
|
-
|
620
|
-
def test_validate_presence_of_parent_works_with_inverse_of
|
621
|
-
Man.accepts_nested_attributes_for(:interests)
|
622
|
-
assert_equal :man, Man.reflect_on_association(:interests).options[:inverse_of]
|
623
|
-
assert_equal :interests, Interest.reflect_on_association(:man).options[:inverse_of]
|
624
|
-
|
625
|
-
repair_validations(Interest) do
|
626
|
-
Interest.validates_presence_of(:man)
|
627
|
-
assert_difference 'Man.count' do
|
628
|
-
assert_difference 'Interest.count', 2 do
|
629
|
-
man = Man.create!(:name => 'John',
|
630
|
-
:interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}])
|
631
|
-
assert_equal 2, man.interests.count
|
632
|
-
end
|
633
|
-
end
|
634
|
-
end
|
635
|
-
end
|
636
|
-
|
637
|
-
def test_validate_presence_of_parent_fails_without_inverse_of
|
638
|
-
Man.accepts_nested_attributes_for(:interests)
|
639
|
-
Man.reflect_on_association(:interests).options.delete(:inverse_of)
|
640
|
-
Interest.reflect_on_association(:man).options.delete(:inverse_of)
|
641
|
-
|
642
|
-
repair_validations(Interest) do
|
643
|
-
Interest.validates_presence_of(:man)
|
644
|
-
assert_no_difference ['Man.count', 'Interest.count'] do
|
645
|
-
man = Man.create(:name => 'John',
|
646
|
-
:interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}])
|
647
|
-
assert !man.errors[:'interests.man'].empty?
|
648
|
-
end
|
649
|
-
end
|
650
|
-
# restore :inverse_of
|
651
|
-
Man.reflect_on_association(:interests).options[:inverse_of] = :man
|
652
|
-
Interest.reflect_on_association(:man).options[:inverse_of] = :interests
|
653
|
-
end
|
654
|
-
|
655
|
-
private
|
656
|
-
|
657
|
-
def association_setter
|
658
|
-
@association_setter ||= "#{@association_name}_attributes=".to_sym
|
659
|
-
end
|
660
|
-
|
661
|
-
def association_getter
|
662
|
-
@association_getter ||= "#{@association_name}_attributes".to_sym
|
663
|
-
end
|
664
|
-
end
|
665
|
-
|
666
|
-
class TestNestedAttributesOnAHasManyAssociation < ActiveRecord::TestCase
|
667
|
-
def setup
|
668
|
-
@association_type = :has_many
|
669
|
-
@association_name = :birds
|
670
|
-
|
671
|
-
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
672
|
-
@pirate.birds.create!(:name => 'Posideons Killer')
|
673
|
-
@pirate.birds.create!(:name => 'Killer bandita Dionne')
|
674
|
-
|
675
|
-
@child_1, @child_2 = @pirate.birds
|
676
|
-
|
677
|
-
@alternate_params = {
|
678
|
-
:birds_attributes => {
|
679
|
-
'foo' => { :id => @child_1.id, :name => 'Grace OMalley' },
|
680
|
-
'bar' => { :id => @child_2.id, :name => 'Privateers Greed' }
|
681
|
-
}
|
682
|
-
}
|
683
|
-
end
|
684
|
-
|
685
|
-
include NestedAttributesOnACollectionAssociationTests
|
686
|
-
end
|
687
|
-
|
688
|
-
class TestNestedAttributesOnAHasAndBelongsToManyAssociation < ActiveRecord::TestCase
|
689
|
-
def setup
|
690
|
-
@association_type = :has_and_belongs_to_many
|
691
|
-
@association_name = :parrots
|
692
|
-
|
693
|
-
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
694
|
-
@pirate.parrots.create!(:name => 'Posideons Killer')
|
695
|
-
@pirate.parrots.create!(:name => 'Killer bandita Dionne')
|
696
|
-
|
697
|
-
@child_1, @child_2 = @pirate.parrots
|
698
|
-
|
699
|
-
@alternate_params = {
|
700
|
-
:parrots_attributes => {
|
701
|
-
'foo' => { :id => @child_1.id, :name => 'Grace OMalley' },
|
702
|
-
'bar' => { :id => @child_2.id, :name => 'Privateers Greed' }
|
703
|
-
}
|
704
|
-
}
|
705
|
-
end
|
706
|
-
|
707
|
-
include NestedAttributesOnACollectionAssociationTests
|
708
|
-
end
|
709
|
-
|
710
|
-
class TestNestedAttributesLimit < ActiveRecord::TestCase
|
711
|
-
def setup
|
712
|
-
Pirate.accepts_nested_attributes_for :parrots, :limit => 2
|
713
|
-
|
714
|
-
@pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
|
715
|
-
end
|
716
|
-
|
717
|
-
def teardown
|
718
|
-
Pirate.accepts_nested_attributes_for :parrots, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
|
719
|
-
end
|
720
|
-
|
721
|
-
def test_limit_with_less_records
|
722
|
-
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Big Big Love' } } }
|
723
|
-
assert_difference('Parrot.count') { @pirate.save! }
|
724
|
-
end
|
725
|
-
|
726
|
-
def test_limit_with_number_exact_records
|
727
|
-
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' }, 'bar' => { :name => 'Blown Away' } } }
|
728
|
-
assert_difference('Parrot.count', 2) { @pirate.save! }
|
729
|
-
end
|
730
|
-
|
731
|
-
def test_limit_with_exceeding_records
|
732
|
-
assert_raises(ActiveRecord::NestedAttributes::TooManyRecords) do
|
733
|
-
@pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' },
|
734
|
-
'bar' => { :name => 'Blown Away' },
|
735
|
-
'car' => { :name => 'The Happening' }} }
|
736
|
-
end
|
737
|
-
end
|
738
|
-
end
|
739
|
-
|
740
|
-
class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase
|
741
|
-
fixtures :owners, :pets
|
742
|
-
|
743
|
-
def setup
|
744
|
-
Owner.accepts_nested_attributes_for :pets
|
745
|
-
|
746
|
-
@owner = owners(:ashley)
|
747
|
-
@pet1, @pet2 = pets(:chew), pets(:mochi)
|
748
|
-
|
749
|
-
@params = {
|
750
|
-
:pets_attributes => {
|
751
|
-
'0' => { :id => @pet1.id, :name => 'Foo' },
|
752
|
-
'1' => { :id => @pet2.id, :name => 'Bar' }
|
753
|
-
}
|
754
|
-
}
|
755
|
-
end
|
756
|
-
|
757
|
-
def test_should_update_existing_records_with_non_standard_primary_key
|
758
|
-
@owner.update_attributes(@params)
|
759
|
-
assert_equal ['Foo', 'Bar'], @owner.pets.map(&:name)
|
760
|
-
end
|
761
|
-
end
|
762
|
-
|
763
|
-
class TestHasOneAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase
|
764
|
-
self.use_transactional_fixtures = false
|
765
|
-
|
766
|
-
def setup
|
767
|
-
@pirate = Pirate.create!(:catchphrase => "My baby takes tha mornin' train!")
|
768
|
-
@ship = @pirate.create_ship(:name => "The good ship Dollypop")
|
769
|
-
@part = @ship.parts.create!(:name => "Mast")
|
770
|
-
@trinket = @part.trinkets.create!(:name => "Necklace")
|
771
|
-
end
|
772
|
-
|
773
|
-
test "when great-grandchild changed in memory, saving parent should save great-grandchild" do
|
774
|
-
@trinket.name = "changed"
|
775
|
-
@pirate.save
|
776
|
-
assert_equal "changed", @trinket.reload.name
|
777
|
-
end
|
778
|
-
|
779
|
-
test "when great-grandchild changed via attributes, saving parent should save great-grandchild" do
|
780
|
-
@pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]}}
|
781
|
-
@pirate.save
|
782
|
-
assert_equal "changed", @trinket.reload.name
|
783
|
-
end
|
784
|
-
|
785
|
-
test "when great-grandchild marked_for_destruction via attributes, saving parent should destroy great-grandchild" do
|
786
|
-
@pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]}}
|
787
|
-
assert_difference('@part.trinkets.count', -1) { @pirate.save }
|
788
|
-
end
|
789
|
-
|
790
|
-
test "when great-grandchild added via attributes, saving parent should create great-grandchild" do
|
791
|
-
@pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]}}
|
792
|
-
assert_difference('@part.trinkets.count', 1) { @pirate.save }
|
793
|
-
end
|
794
|
-
|
795
|
-
test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do
|
796
|
-
@trinket.name = "changed"
|
797
|
-
Ship.create!(:pirate => @pirate, :name => "The Black Rock")
|
798
|
-
ShipPart.create!(:ship => @ship, :name => "Stern")
|
799
|
-
assert_no_queries { @pirate.valid? }
|
800
|
-
end
|
801
|
-
end
|
802
|
-
|
803
|
-
class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase
|
804
|
-
self.use_transactional_fixtures = false
|
805
|
-
|
806
|
-
def setup
|
807
|
-
@ship = Ship.create!(:name => "The good ship Dollypop")
|
808
|
-
@part = @ship.parts.create!(:name => "Mast")
|
809
|
-
@trinket = @part.trinkets.create!(:name => "Necklace")
|
810
|
-
end
|
811
|
-
|
812
|
-
test "when grandchild changed in memory, saving parent should save grandchild" do
|
813
|
-
@trinket.name = "changed"
|
814
|
-
@ship.save
|
815
|
-
assert_equal "changed", @trinket.reload.name
|
816
|
-
end
|
817
|
-
|
818
|
-
test "when grandchild changed via attributes, saving parent should save grandchild" do
|
819
|
-
@ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]}
|
820
|
-
@ship.save
|
821
|
-
assert_equal "changed", @trinket.reload.name
|
822
|
-
end
|
823
|
-
|
824
|
-
test "when grandchild marked_for_destruction via attributes, saving parent should destroy grandchild" do
|
825
|
-
@ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]}
|
826
|
-
assert_difference('@part.trinkets.count', -1) { @ship.save }
|
827
|
-
end
|
828
|
-
|
829
|
-
test "when grandchild added via attributes, saving parent should create grandchild" do
|
830
|
-
@ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]}
|
831
|
-
assert_difference('@part.trinkets.count', 1) { @ship.save }
|
832
|
-
end
|
833
|
-
|
834
|
-
test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do
|
835
|
-
@trinket.name = "changed"
|
836
|
-
Ship.create!(:name => "The Black Rock")
|
837
|
-
ShipPart.create!(:ship => @ship, :name => "Stern")
|
838
|
-
assert_no_queries { @ship.valid? }
|
839
|
-
end
|
840
|
-
end
|