mongoid 3.1.5 → 8.0.2
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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +636 -33
- data/LICENSE +2 -1
- data/README.md +32 -24
- data/Rakefile +75 -5
- data/lib/config/locales/en.yml +301 -132
- data/lib/mongoid/association/accessors.rb +431 -0
- data/lib/mongoid/association/bindable.rb +227 -0
- data/lib/mongoid/association/builders.rb +86 -0
- data/lib/mongoid/association/constrainable.rb +42 -0
- data/lib/mongoid/association/depending.rb +128 -0
- data/lib/mongoid/association/eager_loadable.rb +57 -0
- data/lib/mongoid/association/embedded/batchable.rb +398 -0
- data/lib/mongoid/association/embedded/cyclic.rb +102 -0
- data/lib/mongoid/association/embedded/embedded_in/binding.rb +74 -0
- data/lib/mongoid/association/embedded/embedded_in/buildable.rb +38 -0
- data/lib/mongoid/association/embedded/embedded_in/proxy.rb +111 -0
- data/lib/mongoid/association/embedded/embedded_in.rb +135 -0
- data/lib/mongoid/association/embedded/embeds_many/binding.rb +42 -0
- data/lib/mongoid/association/embedded/embeds_many/buildable.rb +45 -0
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +571 -0
- data/lib/mongoid/association/embedded/embeds_many.rb +183 -0
- data/lib/mongoid/association/embedded/embeds_one/binding.rb +43 -0
- data/lib/mongoid/association/embedded/embeds_one/buildable.rb +53 -0
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +164 -0
- data/lib/mongoid/association/embedded/embeds_one.rb +150 -0
- data/lib/mongoid/association/embedded.rb +6 -0
- data/lib/mongoid/association/macros.rb +228 -0
- data/lib/mongoid/association/many.rb +202 -0
- data/lib/mongoid/association/marshalable.rb +31 -0
- data/lib/mongoid/association/nested/many.rb +192 -0
- data/lib/mongoid/association/nested/nested_buildable.rb +66 -0
- data/lib/mongoid/association/nested/one.rb +116 -0
- data/lib/mongoid/association/nested.rb +15 -0
- data/lib/mongoid/association/one.rb +53 -0
- data/lib/mongoid/association/options.rb +122 -0
- data/lib/mongoid/association/proxy.rb +200 -0
- data/lib/mongoid/association/referenced/auto_save.rb +74 -0
- data/lib/mongoid/association/referenced/belongs_to/binding.rb +83 -0
- data/lib/mongoid/association/referenced/belongs_to/buildable.rb +48 -0
- data/lib/mongoid/association/referenced/belongs_to/eager.rb +73 -0
- data/lib/mongoid/association/referenced/belongs_to/proxy.rb +124 -0
- data/lib/mongoid/association/referenced/belongs_to.rb +226 -0
- data/lib/mongoid/association/referenced/counter_cache.rb +152 -0
- data/lib/mongoid/association/referenced/eager.rb +163 -0
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +72 -0
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +40 -0
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +53 -0
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +345 -0
- data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +273 -0
- data/lib/mongoid/association/referenced/has_many/binding.rb +36 -0
- data/lib/mongoid/association/referenced/has_many/buildable.rb +38 -0
- data/lib/mongoid/association/referenced/has_many/eager.rb +44 -0
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +494 -0
- data/lib/mongoid/association/referenced/has_many/proxy.rb +551 -0
- data/lib/mongoid/association/referenced/has_many.rb +251 -0
- data/lib/mongoid/association/referenced/has_one/binding.rb +42 -0
- data/lib/mongoid/association/referenced/has_one/buildable.rb +74 -0
- data/lib/mongoid/association/referenced/has_one/eager.rb +36 -0
- data/lib/mongoid/association/referenced/has_one/nested_builder.rb +113 -0
- data/lib/mongoid/association/referenced/has_one/proxy.rb +108 -0
- data/lib/mongoid/association/referenced/has_one.rb +184 -0
- data/lib/mongoid/association/referenced/syncable.rb +155 -0
- data/lib/mongoid/association/referenced.rb +9 -0
- data/lib/mongoid/association/reflections.rb +69 -0
- data/lib/mongoid/association/relatable.rb +489 -0
- data/lib/mongoid/association.rb +135 -0
- data/lib/mongoid/atomic/modifiers.rb +41 -61
- data/lib/mongoid/atomic/paths/embedded/many.rb +24 -8
- data/lib/mongoid/atomic/paths/embedded/one.rb +5 -8
- data/lib/mongoid/atomic/paths/embedded.rb +3 -34
- data/lib/mongoid/atomic/paths/root.rb +4 -20
- data/lib/mongoid/atomic/paths.rb +2 -1
- data/lib/mongoid/atomic.rb +52 -69
- data/lib/mongoid/attributes/dynamic.rb +141 -0
- data/lib/mongoid/attributes/nested.rb +93 -0
- data/lib/mongoid/attributes/processing.rb +35 -97
- data/lib/mongoid/attributes/projector.rb +119 -0
- data/lib/mongoid/attributes/readonly.rb +27 -10
- data/lib/mongoid/attributes.rb +159 -181
- data/lib/mongoid/cacheable.rb +33 -0
- data/lib/mongoid/changeable.rb +420 -0
- data/lib/mongoid/clients/factory.rb +105 -0
- data/lib/mongoid/clients/options.rb +111 -0
- data/lib/mongoid/clients/sessions.rb +113 -0
- data/lib/mongoid/clients/storage_options.rb +79 -0
- data/lib/mongoid/clients/validators/storage.rb +58 -0
- data/lib/mongoid/clients/validators.rb +3 -0
- data/lib/mongoid/clients.rb +79 -0
- data/lib/mongoid/composable.rb +128 -0
- data/lib/mongoid/config/environment.rb +51 -13
- data/lib/mongoid/config/options.rb +30 -18
- data/lib/mongoid/config/validators/client.rb +128 -0
- data/lib/mongoid/config/validators/option.rb +3 -4
- data/lib/mongoid/config/validators.rb +3 -2
- data/lib/mongoid/config.rb +170 -89
- data/lib/mongoid/contextual/aggregable/memory.rb +40 -27
- data/lib/mongoid/contextual/aggregable/mongo.rb +33 -36
- data/lib/mongoid/contextual/aggregable/none.rb +65 -0
- data/lib/mongoid/contextual/aggregable.rb +17 -0
- data/lib/mongoid/contextual/atomic.rb +80 -79
- data/lib/mongoid/contextual/command.rb +8 -11
- data/lib/mongoid/contextual/geo_near.rb +42 -44
- data/lib/mongoid/contextual/map_reduce.rb +33 -127
- data/lib/mongoid/contextual/memory.rb +226 -88
- data/lib/mongoid/contextual/mongo.rb +466 -293
- data/lib/mongoid/contextual/none.rb +193 -0
- data/lib/mongoid/contextual/queryable.rb +3 -4
- data/lib/mongoid/contextual.rb +11 -11
- data/lib/mongoid/copyable.rb +68 -20
- data/lib/mongoid/criteria/findable.rb +143 -0
- data/lib/mongoid/criteria/includable.rb +92 -0
- data/lib/mongoid/criteria/inspectable.rb +24 -0
- data/lib/mongoid/criteria/marshalable.rb +55 -0
- data/lib/mongoid/criteria/modifiable.rb +235 -0
- data/lib/mongoid/criteria/options.rb +24 -0
- data/lib/mongoid/criteria/permission.rb +71 -0
- data/lib/mongoid/criteria/queryable/aggregable.rb +109 -0
- data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
- data/lib/mongoid/criteria/queryable/extensions/array.rb +151 -0
- data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +57 -0
- data/lib/mongoid/criteria/queryable/extensions/boolean.rb +33 -0
- data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
- data/lib/mongoid/criteria/queryable/extensions/date_time.rb +52 -0
- data/lib/mongoid/criteria/queryable/extensions/hash.rb +163 -0
- data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +75 -0
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +81 -0
- data/lib/mongoid/criteria/queryable/extensions/object.rb +182 -0
- data/lib/mongoid/criteria/queryable/extensions/range.rb +102 -0
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +72 -0
- data/lib/mongoid/criteria/queryable/extensions/set.rb +33 -0
- data/lib/mongoid/criteria/queryable/extensions/string.rb +122 -0
- data/lib/mongoid/criteria/queryable/extensions/symbol.rb +74 -0
- data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +66 -0
- data/lib/mongoid/criteria/queryable/extensions.rb +25 -0
- data/lib/mongoid/criteria/queryable/key.rb +177 -0
- data/lib/mongoid/criteria/queryable/macroable.rb +26 -0
- data/lib/mongoid/criteria/queryable/mergeable.rb +434 -0
- data/lib/mongoid/criteria/queryable/optional.rb +380 -0
- data/lib/mongoid/criteria/queryable/options.rb +136 -0
- data/lib/mongoid/criteria/queryable/pipeline.rb +106 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +937 -0
- data/lib/mongoid/criteria/queryable/selector.rb +287 -0
- data/lib/mongoid/criteria/queryable/smash.rb +128 -0
- data/lib/mongoid/criteria/queryable/storable.rb +237 -0
- data/lib/mongoid/criteria/queryable.rb +90 -0
- data/lib/mongoid/criteria/scopable.rb +166 -0
- data/lib/mongoid/criteria.rb +177 -189
- data/lib/mongoid/deprecable.rb +36 -0
- data/lib/mongoid/deprecation.rb +25 -0
- data/lib/mongoid/document.rb +193 -139
- data/lib/mongoid/equality.rb +35 -18
- data/lib/mongoid/errors/ambiguous_relationship.rb +5 -6
- data/lib/mongoid/errors/callback.rb +2 -3
- data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
- data/lib/mongoid/errors/delete_restriction.rb +10 -13
- data/lib/mongoid/errors/document_not_destroyed.rb +22 -0
- data/lib/mongoid/errors/document_not_found.rb +36 -21
- data/lib/mongoid/errors/empty_config_file.rb +25 -0
- data/lib/mongoid/errors/in_memory_collation_not_supported.rb +19 -0
- data/lib/mongoid/errors/invalid_collection.rb +2 -1
- data/lib/mongoid/errors/invalid_config_file.rb +25 -0
- data/lib/mongoid/errors/invalid_config_option.rb +3 -4
- data/lib/mongoid/errors/invalid_dependent_strategy.rb +31 -0
- data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
- data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
- data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
- data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
- data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
- data/lib/mongoid/errors/invalid_field.rb +10 -9
- data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
- data/lib/mongoid/errors/invalid_field_option.rb +2 -3
- data/lib/mongoid/errors/invalid_field_type.rb +26 -0
- data/lib/mongoid/errors/invalid_find.rb +2 -3
- data/lib/mongoid/errors/invalid_includes.rb +2 -3
- data/lib/mongoid/errors/invalid_index.rb +2 -3
- data/lib/mongoid/errors/invalid_options.rb +4 -5
- data/lib/mongoid/errors/invalid_path.rb +2 -3
- data/lib/mongoid/errors/invalid_persistence_option.rb +26 -0
- data/lib/mongoid/errors/invalid_query.rb +40 -0
- data/lib/mongoid/errors/invalid_relation.rb +61 -0
- data/lib/mongoid/errors/invalid_relation_option.rb +28 -0
- data/lib/mongoid/errors/invalid_scope.rb +2 -3
- data/lib/mongoid/errors/invalid_session_use.rb +21 -0
- data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +6 -5
- data/lib/mongoid/errors/invalid_storage_options.rb +4 -5
- data/lib/mongoid/errors/invalid_storage_parent.rb +25 -0
- data/lib/mongoid/errors/invalid_time.rb +2 -3
- data/lib/mongoid/errors/inverse_not_found.rb +4 -5
- data/lib/mongoid/errors/mixed_client_configuration.rb +27 -0
- data/lib/mongoid/errors/mixed_relations.rb +2 -3
- data/lib/mongoid/errors/mongoid_error.rb +22 -23
- data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +3 -4
- data/lib/mongoid/errors/no_client_config.rb +21 -0
- data/lib/mongoid/errors/no_client_database.rb +26 -0
- data/lib/mongoid/errors/no_client_hosts.rb +26 -0
- data/lib/mongoid/errors/no_clients_config.rb +19 -0
- data/lib/mongoid/errors/no_default_client.rb +22 -0
- data/lib/mongoid/errors/no_environment.rb +2 -3
- data/lib/mongoid/errors/no_map_reduce_output.rb +2 -3
- data/lib/mongoid/errors/no_metadata.rb +2 -3
- data/lib/mongoid/errors/no_parent.rb +2 -3
- data/lib/mongoid/errors/readonly_attribute.rb +3 -4
- data/lib/mongoid/errors/readonly_document.rb +21 -0
- data/lib/mongoid/errors/scope_overwrite.rb +2 -1
- data/lib/mongoid/errors/too_many_nested_attribute_records.rb +3 -1
- data/lib/mongoid/errors/unknown_attribute.rb +3 -4
- data/lib/mongoid/errors/unknown_model.rb +24 -0
- data/lib/mongoid/errors/unsaved_document.rb +3 -2
- data/lib/mongoid/errors/unsupported_javascript.rb +2 -3
- data/lib/mongoid/errors/validations.rb +2 -1
- data/lib/mongoid/errors.rb +30 -9
- data/lib/mongoid/evolvable.rb +4 -5
- data/lib/mongoid/extensions/array.rb +45 -52
- data/lib/mongoid/extensions/big_decimal.rb +41 -22
- data/lib/mongoid/extensions/binary.rb +42 -0
- data/lib/mongoid/extensions/boolean.rb +19 -17
- data/lib/mongoid/extensions/date.rb +33 -23
- data/lib/mongoid/extensions/date_time.rb +5 -13
- data/lib/mongoid/extensions/decimal128.rb +36 -0
- data/lib/mongoid/extensions/false_class.rb +5 -8
- data/lib/mongoid/extensions/float.rb +11 -16
- data/lib/mongoid/extensions/hash.rb +88 -49
- data/lib/mongoid/extensions/integer.rb +10 -18
- data/lib/mongoid/extensions/module.rb +3 -4
- data/lib/mongoid/extensions/nil_class.rb +2 -5
- data/lib/mongoid/extensions/object.rb +38 -62
- data/lib/mongoid/extensions/object_id.rb +7 -12
- data/lib/mongoid/extensions/range.rb +46 -17
- data/lib/mongoid/extensions/regexp.rb +15 -8
- data/lib/mongoid/extensions/set.rb +17 -15
- data/lib/mongoid/extensions/string.rb +40 -80
- data/lib/mongoid/extensions/symbol.rb +7 -23
- data/lib/mongoid/extensions/time.rb +42 -25
- data/lib/mongoid/extensions/time_with_zone.rb +27 -10
- data/lib/mongoid/extensions/true_class.rb +5 -8
- data/lib/mongoid/extensions.rb +31 -13
- data/lib/mongoid/factory.rb +99 -11
- data/lib/mongoid/fields/foreign_key.rb +26 -34
- data/lib/mongoid/fields/localized.rb +24 -13
- data/lib/mongoid/fields/standard.rb +19 -73
- data/lib/mongoid/fields/validators/macro.rb +56 -15
- data/lib/mongoid/fields/validators.rb +2 -1
- data/lib/mongoid/fields.rb +342 -87
- data/lib/mongoid/findable.rb +219 -0
- data/lib/mongoid/indexable/specification.rb +103 -0
- data/lib/mongoid/indexable/validators/options.rb +110 -0
- data/lib/mongoid/indexable.rb +148 -0
- data/lib/mongoid/inspectable.rb +52 -0
- data/lib/mongoid/interceptable.rb +312 -0
- data/lib/mongoid/loggable.rb +15 -18
- data/lib/mongoid/matchable.rb +23 -0
- data/lib/mongoid/matcher/all.rb +22 -0
- data/lib/mongoid/matcher/and.rb +21 -0
- data/lib/mongoid/matcher/bits.rb +41 -0
- data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
- data/lib/mongoid/matcher/bits_all_set.rb +20 -0
- data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
- data/lib/mongoid/matcher/bits_any_set.rb +20 -0
- data/lib/mongoid/matcher/elem_match.rb +36 -0
- data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
- data/lib/mongoid/matcher/eq.rb +11 -0
- data/lib/mongoid/matcher/eq_impl.rb +67 -0
- data/lib/mongoid/matcher/eq_impl_with_regexp.rb +26 -0
- data/lib/mongoid/matcher/exists.rb +15 -0
- data/lib/mongoid/matcher/expression.rb +35 -0
- data/lib/mongoid/matcher/expression_operator.rb +19 -0
- data/lib/mongoid/matcher/field_expression.rb +62 -0
- data/lib/mongoid/matcher/field_operator.rb +54 -0
- data/lib/mongoid/matcher/gt.rb +17 -0
- data/lib/mongoid/matcher/gte.rb +17 -0
- data/lib/mongoid/matcher/in.rb +25 -0
- data/lib/mongoid/matcher/lt.rb +17 -0
- data/lib/mongoid/matcher/lte.rb +17 -0
- data/lib/mongoid/matcher/mod.rb +17 -0
- data/lib/mongoid/matcher/ne.rb +16 -0
- data/lib/mongoid/matcher/nin.rb +11 -0
- data/lib/mongoid/matcher/nor.rb +25 -0
- data/lib/mongoid/matcher/not.rb +29 -0
- data/lib/mongoid/matcher/or.rb +21 -0
- data/lib/mongoid/matcher/regex.rb +41 -0
- data/lib/mongoid/matcher/size.rb +26 -0
- data/lib/mongoid/matcher/type.rb +99 -0
- data/lib/mongoid/matcher.rb +115 -0
- data/lib/mongoid/persistable/creatable.rb +181 -0
- data/lib/mongoid/persistable/deletable.rb +132 -0
- data/lib/mongoid/persistable/destroyable.rb +57 -0
- data/lib/mongoid/persistable/incrementable.rb +35 -0
- data/lib/mongoid/persistable/logical.rb +36 -0
- data/lib/mongoid/persistable/poppable.rb +36 -0
- data/lib/mongoid/persistable/pullable.rb +50 -0
- data/lib/mongoid/persistable/pushable.rb +66 -0
- data/lib/mongoid/persistable/renamable.rb +37 -0
- data/lib/mongoid/persistable/savable.rb +47 -0
- data/lib/mongoid/persistable/settable.rb +93 -0
- data/lib/mongoid/persistable/unsettable.rb +36 -0
- data/lib/mongoid/persistable/updatable.rb +165 -0
- data/lib/mongoid/persistable/upsertable.rb +51 -0
- data/lib/mongoid/persistable.rb +305 -0
- data/lib/mongoid/persistence_context.rb +239 -0
- data/lib/mongoid/positional.rb +72 -0
- data/lib/mongoid/query_cache.rb +64 -0
- data/lib/mongoid/railtie.rb +35 -78
- data/lib/mongoid/railties/controller_runtime.rb +88 -0
- data/lib/mongoid/railties/database.rake +18 -25
- data/lib/mongoid/reloadable.rb +94 -0
- data/lib/mongoid/scopable.rb +324 -0
- data/lib/mongoid/selectable.rb +49 -0
- data/lib/mongoid/serializable.rb +170 -0
- data/lib/mongoid/shardable.rb +130 -0
- data/lib/mongoid/stateful.rb +134 -0
- data/lib/mongoid/stringified_symbol.rb +52 -0
- data/lib/mongoid/tasks/database.rake +38 -0
- data/lib/mongoid/tasks/database.rb +194 -0
- data/lib/mongoid/threaded/lifecycle.rb +28 -70
- data/lib/mongoid/threaded.rb +142 -219
- data/lib/mongoid/timestamps/created/short.rb +2 -1
- data/lib/mongoid/timestamps/created.rb +9 -5
- data/lib/mongoid/timestamps/short.rb +2 -1
- data/lib/mongoid/timestamps/timeless.rb +52 -16
- data/lib/mongoid/timestamps/updated/short.rb +4 -3
- data/lib/mongoid/timestamps/updated.rb +14 -9
- data/lib/mongoid/timestamps.rb +4 -3
- data/lib/mongoid/touchable.rb +131 -0
- data/lib/mongoid/traversable.rb +337 -0
- data/lib/mongoid/validatable/associated.rb +47 -0
- data/lib/mongoid/validatable/format.rb +21 -0
- data/lib/mongoid/validatable/length.rb +21 -0
- data/lib/mongoid/validatable/localizable.rb +29 -0
- data/lib/mongoid/validatable/macros.rb +89 -0
- data/lib/mongoid/validatable/presence.rb +81 -0
- data/lib/mongoid/validatable/queryable.rb +29 -0
- data/lib/mongoid/validatable/uniqueness.rb +304 -0
- data/lib/mongoid/validatable.rb +160 -0
- data/lib/mongoid/version.rb +3 -2
- data/lib/mongoid/warnings.rb +28 -0
- data/lib/mongoid.rb +68 -109
- data/lib/rails/generators/mongoid/config/config_generator.rb +10 -2
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +150 -45
- data/lib/rails/generators/mongoid/model/model_generator.rb +3 -3
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -4
- data/lib/rails/generators/mongoid_generator.rb +5 -41
- data/lib/rails/mongoid.rb +6 -129
- data/spec/README.md +33 -0
- data/spec/config/mongoid.yml +56 -25
- data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
- data/spec/integration/app_spec.rb +345 -0
- data/spec/integration/associations/belongs_to_spec.rb +33 -0
- data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
- data/spec/integration/associations/embedded_spec.rb +283 -0
- data/spec/integration/associations/embeds_many_spec.rb +219 -0
- data/spec/integration/associations/embeds_one_spec.rb +41 -0
- data/spec/integration/associations/foreign_key_spec.rb +107 -0
- data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
- data/spec/integration/associations/has_many_spec.rb +128 -0
- data/spec/integration/associations/has_one_spec.rb +272 -0
- data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
- data/spec/integration/associations/reverse_population_spec.rb +34 -0
- data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
- data/spec/integration/associations/scope_option_spec.rb +101 -0
- data/spec/integration/atomic/modifiers_spec.rb +116 -0
- data/spec/integration/bson_regexp_raw_spec.rb +19 -0
- data/spec/integration/callbacks_models.rb +155 -0
- data/spec/integration/callbacks_spec.rb +450 -0
- data/spec/integration/contextual/empty_spec.rb +141 -0
- data/spec/integration/criteria/alias_query_spec.rb +161 -0
- data/spec/integration/criteria/date_field_spec.rb +40 -0
- data/spec/integration/criteria/default_scope_spec.rb +72 -0
- data/spec/integration/criteria/logical_spec.rb +124 -0
- data/spec/integration/criteria/range_spec.rb +359 -0
- data/spec/integration/criteria/time_with_zone_spec.rb +142 -0
- data/spec/integration/discriminator_key_spec.rb +392 -0
- data/spec/integration/discriminator_value_spec.rb +206 -0
- data/spec/integration/document_spec.rb +51 -0
- data/spec/integration/dots_and_dollars_spec.rb +277 -0
- data/spec/integration/i18n_fallbacks_spec.rb +89 -0
- data/spec/integration/matcher_examples_spec.rb +765 -0
- data/spec/integration/matcher_operator_data/all.yml +140 -0
- data/spec/integration/matcher_operator_data/and.yml +93 -0
- data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
- data/spec/integration/matcher_operator_data/comment.yml +22 -0
- data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
- data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
- data/spec/integration/matcher_operator_data/eq.yml +191 -0
- data/spec/integration/matcher_operator_data/exists.yml +213 -0
- data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
- data/spec/integration/matcher_operator_data/gt.yml +132 -0
- data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
- data/spec/integration/matcher_operator_data/gte.yml +132 -0
- data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
- data/spec/integration/matcher_operator_data/implicit.yml +331 -0
- data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
- data/spec/integration/matcher_operator_data/in.yml +210 -0
- data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
- data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
- data/spec/integration/matcher_operator_data/lt.yml +132 -0
- data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
- data/spec/integration/matcher_operator_data/lte.yml +132 -0
- data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
- data/spec/integration/matcher_operator_data/mod.yml +55 -0
- data/spec/integration/matcher_operator_data/multiple.yml +29 -0
- data/spec/integration/matcher_operator_data/ne.yml +150 -0
- data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
- data/spec/integration/matcher_operator_data/nin.yml +114 -0
- data/spec/integration/matcher_operator_data/nor.yml +126 -0
- data/spec/integration/matcher_operator_data/not.yml +196 -0
- data/spec/integration/matcher_operator_data/or.yml +137 -0
- data/spec/integration/matcher_operator_data/regex.yml +174 -0
- data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
- data/spec/integration/matcher_operator_data/size.yml +174 -0
- data/spec/integration/matcher_operator_data/type.yml +70 -0
- data/spec/integration/matcher_operator_data/type_array.yml +16 -0
- data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
- data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
- data/spec/integration/matcher_operator_data/type_code.yml +26 -0
- data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
- data/spec/integration/matcher_operator_data/type_date.yml +39 -0
- data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
- data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
- data/spec/integration/matcher_operator_data/type_double.yml +15 -0
- data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
- data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
- data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
- data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
- data/spec/integration/matcher_operator_data/type_null.yml +23 -0
- data/spec/integration/matcher_operator_data/type_object.yml +23 -0
- data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
- data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
- data/spec/integration/matcher_operator_data/type_string.yml +15 -0
- data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
- data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
- data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
- data/spec/integration/matcher_operator_spec.rb +122 -0
- data/spec/integration/matcher_spec.rb +283 -0
- data/spec/integration/persistence/range_field_spec.rb +350 -0
- data/spec/integration/server_query_spec.rb +141 -0
- data/spec/integration/shardable_spec.rb +148 -0
- data/spec/integration/stringified_symbol_field_spec.rb +203 -0
- data/spec/lite_spec_helper.rb +83 -0
- data/spec/mongoid/association/accessors_spec.rb +1067 -0
- data/spec/mongoid/association/auto_save_spec.rb +403 -0
- data/spec/mongoid/association/builders_spec.rb +255 -0
- data/spec/mongoid/association/constrainable_spec.rb +117 -0
- data/spec/mongoid/association/counter_cache_spec.rb +452 -0
- data/spec/mongoid/association/depending_spec.rb +959 -0
- data/spec/mongoid/association/eager_spec.rb +282 -0
- data/spec/mongoid/association/embedded/cyclic_spec.rb +180 -0
- data/spec/mongoid/association/embedded/dirty_spec.rb +67 -0
- data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +174 -0
- data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +90 -0
- data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +619 -0
- data/spec/mongoid/association/embedded/embedded_in_spec.rb +903 -0
- data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +56 -0
- data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +218 -0
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +4863 -0
- data/spec/mongoid/association/embedded/embeds_many_models.rb +226 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +932 -0
- data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +79 -0
- data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +106 -0
- data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +1025 -0
- data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +8 -0
- data/spec/mongoid/association/embedded/embeds_one_models.rb +73 -0
- data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +984 -0
- data/spec/mongoid/association/macros_spec.rb +1116 -0
- data/spec/mongoid/association/nested/many_spec.rb +232 -0
- data/spec/mongoid/association/nested/one_spec.rb +253 -0
- data/spec/mongoid/association/options_spec.rb +1323 -0
- data/spec/mongoid/association/polymorphic_spec.rb +162 -0
- data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +244 -0
- data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +292 -0
- data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +412 -0
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +1388 -0
- data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
- data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +2046 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +180 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +148 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +196 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +76 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +3836 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +92 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +1104 -0
- data/spec/mongoid/association/referenced/has_many/binding_spec.rb +155 -0
- data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +251 -0
- data/spec/mongoid/association/referenced/has_many/eager_spec.rb +290 -0
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2232 -0
- data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +23 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +4161 -0
- data/spec/mongoid/association/referenced/has_many_models.rb +97 -0
- data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
- data/spec/mongoid/association/referenced/has_many_spec.rb +1273 -0
- data/spec/mongoid/association/referenced/has_one/binding_spec.rb +133 -0
- data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +159 -0
- data/spec/mongoid/association/referenced/has_one/eager_spec.rb +193 -0
- data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +1248 -0
- data/spec/mongoid/association/referenced/has_one_models.rb +113 -0
- data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
- data/spec/mongoid/association/referenced/has_one_spec.rb +1383 -0
- data/spec/mongoid/association/reflections_spec.rb +92 -0
- data/spec/mongoid/association/syncable_spec.rb +513 -0
- data/spec/mongoid/association_spec.rb +191 -0
- data/spec/mongoid/atomic/modifiers_spec.rb +88 -39
- data/spec/mongoid/atomic/paths/embedded/many_spec.rb +10 -49
- data/spec/mongoid/atomic/paths/embedded/one_spec.rb +9 -49
- data/spec/mongoid/atomic/paths/root_spec.rb +5 -61
- data/spec/mongoid/atomic/paths_spec.rb +115 -35
- data/spec/mongoid/atomic_spec.rb +89 -42
- data/spec/mongoid/attributes/dynamic_spec.rb +152 -0
- data/spec/mongoid/attributes/nested_spec.rb +5000 -0
- data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
- data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
- data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
- data/spec/mongoid/attributes/projector_spec.rb +40 -0
- data/spec/mongoid/attributes/readonly_spec.rb +166 -64
- data/spec/mongoid/attributes_spec.rb +1418 -409
- data/spec/mongoid/cacheable_spec.rb +114 -0
- data/spec/mongoid/changeable_spec.rb +1914 -0
- data/spec/mongoid/clients/factory_spec.rb +426 -0
- data/spec/mongoid/clients/options_spec.rb +521 -0
- data/spec/mongoid/clients/sessions_spec.rb +297 -0
- data/spec/mongoid/clients/transactions_spec.rb +415 -0
- data/spec/mongoid/clients_spec.rb +1084 -0
- data/spec/mongoid/composable_spec.rb +33 -0
- data/spec/mongoid/config/environment_spec.rb +138 -17
- data/spec/mongoid/config/options_spec.rb +26 -7
- data/spec/mongoid/config_spec.rb +607 -93
- data/spec/mongoid/contextual/aggregable/memory_spec.rb +433 -153
- data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
- data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
- data/spec/mongoid/contextual/aggregable/mongo_spec.rb +221 -56
- data/spec/mongoid/contextual/aggregable/none_spec.rb +60 -0
- data/spec/mongoid/contextual/atomic_spec.rb +577 -162
- data/spec/mongoid/contextual/geo_near_spec.rb +104 -38
- data/spec/mongoid/contextual/map_reduce_spec.rb +137 -142
- data/spec/mongoid/contextual/memory_spec.rb +1880 -269
- data/spec/mongoid/contextual/mongo_spec.rb +2523 -601
- data/spec/mongoid/contextual/none_spec.rb +123 -0
- data/spec/mongoid/copyable_spec.rb +833 -76
- data/spec/mongoid/copyable_spec_models.rb +47 -0
- data/spec/mongoid/criteria/findable_spec.rb +1132 -0
- data/spec/mongoid/criteria/includable_spec.rb +1492 -0
- data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
- data/spec/mongoid/criteria/inspectable_spec.rb +29 -0
- data/spec/mongoid/criteria/marshalable_spec.rb +47 -0
- data/spec/mongoid/criteria/modifiable_spec.rb +1812 -0
- data/spec/mongoid/criteria/options_spec.rb +31 -0
- data/spec/mongoid/criteria/queryable/aggregable_spec.rb +372 -0
- data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
- data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +513 -0
- data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +169 -0
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +60 -0
- data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +215 -0
- data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +343 -0
- data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +434 -0
- data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +60 -0
- data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +67 -0
- data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +314 -0
- data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +67 -0
- data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +79 -0
- data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +119 -0
- data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +110 -0
- data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +370 -0
- data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +91 -0
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +92 -0
- data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +41 -0
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +347 -0
- data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +169 -0
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +406 -0
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +387 -0
- data/spec/mongoid/criteria/queryable/key_spec.rb +96 -0
- data/spec/mongoid/criteria/queryable/mergeable_spec.rb +182 -0
- data/spec/mongoid/criteria/queryable/optional_spec.rb +1317 -0
- data/spec/mongoid/criteria/queryable/options_spec.rb +362 -0
- data/spec/mongoid/criteria/queryable/pipeline_spec.rb +214 -0
- data/spec/mongoid/criteria/queryable/queryable_spec.rb +139 -0
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +2119 -0
- data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +2462 -0
- data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
- data/spec/mongoid/criteria/queryable/selector_spec.rb +895 -0
- data/spec/mongoid/criteria/queryable/smash_spec.rb +32 -0
- data/spec/mongoid/criteria/queryable/storable_spec.rb +226 -0
- data/spec/mongoid/criteria/scopable_spec.rb +601 -0
- data/spec/mongoid/criteria_projection_spec.rb +410 -0
- data/spec/mongoid/criteria_spec.rb +1828 -3572
- data/spec/mongoid/document_fields_spec.rb +262 -0
- data/spec/mongoid/document_persistence_context_spec.rb +32 -0
- data/spec/mongoid/document_query_spec.rb +89 -0
- data/spec/mongoid/document_spec.rb +452 -221
- data/spec/mongoid/equality_spec.rb +155 -52
- data/spec/mongoid/errors/ambiguous_relationship_spec.rb +8 -6
- data/spec/mongoid/errors/callback_spec.rb +5 -3
- data/spec/mongoid/errors/delete_restriction_spec.rb +7 -5
- data/spec/mongoid/errors/document_not_destroyed_spec.rb +35 -0
- data/spec/mongoid/errors/document_not_found_spec.rb +89 -11
- data/spec/mongoid/errors/invalid_collection_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_config_file_spec.rb +31 -0
- data/spec/mongoid/errors/invalid_config_option_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_field_option_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_field_spec.rb +6 -4
- data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
- data/spec/mongoid/errors/invalid_find_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_includes_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_index_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_options_spec.rb +7 -5
- data/spec/mongoid/errors/invalid_path_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_relation_spec.rb +39 -0
- data/spec/mongoid/errors/invalid_scope_spec.rb +7 -5
- data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_storage_options_spec.rb +5 -3
- data/spec/mongoid/errors/invalid_time_spec.rb +5 -3
- data/spec/mongoid/errors/inverse_not_found_spec.rb +6 -4
- data/spec/mongoid/errors/mixed_client_configuration_spec.rb +31 -0
- data/spec/mongoid/errors/mixed_relations_spec.rb +5 -3
- data/spec/mongoid/errors/mongoid_error_spec.rb +45 -10
- data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +8 -6
- data/spec/mongoid/errors/no_client_config_spec.rb +31 -0
- data/spec/mongoid/errors/no_client_database_spec.rb +31 -0
- data/spec/mongoid/errors/no_client_hosts_spec.rb +31 -0
- data/spec/mongoid/errors/no_clients_config_spec.rb +31 -0
- data/spec/mongoid/errors/no_environment_spec.rb +8 -6
- data/spec/mongoid/errors/no_map_reduce_output_spec.rb +5 -3
- data/spec/mongoid/errors/no_metadata_spec.rb +5 -3
- data/spec/mongoid/errors/no_parent_spec.rb +6 -4
- data/spec/mongoid/errors/readonly_attribute_spec.rb +5 -3
- data/spec/mongoid/errors/readonly_document_spec.rb +31 -0
- data/spec/mongoid/errors/scope_overwrite_spec.rb +5 -3
- data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +6 -4
- data/spec/mongoid/errors/unknown_attribute_spec.rb +7 -5
- data/spec/mongoid/errors/unsaved_document_spec.rb +6 -4
- data/spec/mongoid/errors/unsupported_javascript_spec.rb +5 -3
- data/spec/mongoid/errors/validations_spec.rb +9 -7
- data/spec/mongoid/extensions/array_spec.rb +108 -116
- data/spec/mongoid/extensions/big_decimal_spec.rb +838 -49
- data/spec/mongoid/extensions/binary_spec.rb +55 -18
- data/spec/mongoid/extensions/boolean_spec.rb +76 -74
- data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
- data/spec/mongoid/extensions/date_spec.rb +59 -145
- data/spec/mongoid/extensions/date_time_spec.rb +35 -76
- data/spec/mongoid/extensions/decimal128_spec.rb +46 -0
- data/spec/mongoid/extensions/false_class_spec.rb +7 -5
- data/spec/mongoid/extensions/float_spec.rb +69 -62
- data/spec/mongoid/extensions/hash_spec.rb +197 -30
- data/spec/mongoid/extensions/integer_spec.rb +63 -65
- data/spec/mongoid/extensions/module_spec.rb +4 -2
- data/spec/mongoid/extensions/nil_class_spec.rb +3 -1
- data/spec/mongoid/extensions/object_id_spec.rb +136 -134
- data/spec/mongoid/extensions/object_spec.rb +53 -57
- data/spec/mongoid/extensions/range_spec.rb +287 -28
- data/spec/mongoid/extensions/regexp_spec.rb +71 -21
- data/spec/mongoid/extensions/set_spec.rb +112 -4
- data/spec/mongoid/extensions/string_spec.rb +188 -89
- data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
- data/spec/mongoid/extensions/symbol_spec.rb +25 -30
- data/spec/mongoid/extensions/time_spec.rb +703 -110
- data/spec/mongoid/extensions/time_with_zone_spec.rb +82 -67
- data/spec/mongoid/extensions/true_class_spec.rb +7 -5
- data/spec/mongoid/extensions_spec.rb +43 -0
- data/spec/mongoid/factory_spec.rb +374 -25
- data/spec/mongoid/fields/foreign_key_spec.rb +116 -92
- data/spec/mongoid/fields/localized_spec.rb +177 -35
- data/spec/mongoid/fields/standard_spec.rb +15 -13
- data/spec/mongoid/fields_spec.rb +952 -238
- data/spec/mongoid/findable_spec.rb +632 -0
- data/spec/mongoid/indexable/specification_spec.rb +129 -0
- data/spec/mongoid/indexable_spec.rb +643 -0
- data/spec/mongoid/inspectable_spec.rb +86 -0
- data/spec/mongoid/interceptable_spec.rb +2373 -0
- data/spec/mongoid/interceptable_spec_models.rb +307 -0
- data/spec/mongoid/loggable_spec.rb +3 -1
- data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
- data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
- data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
- data/spec/mongoid/mongoizable_spec.rb +285 -0
- data/spec/mongoid/persistable/creatable_spec.rb +662 -0
- data/spec/mongoid/persistable/deletable_spec.rb +514 -0
- data/spec/mongoid/persistable/destroyable_spec.rb +455 -0
- data/spec/mongoid/persistable/incrementable_spec.rb +241 -0
- data/spec/mongoid/persistable/logical_spec.rb +159 -0
- data/spec/mongoid/persistable/poppable_spec.rb +131 -0
- data/spec/mongoid/persistable/pullable_spec.rb +258 -0
- data/spec/mongoid/persistable/pushable_spec.rb +353 -0
- data/spec/mongoid/persistable/renamable_spec.rb +151 -0
- data/spec/mongoid/persistable/savable_spec.rb +684 -0
- data/spec/mongoid/persistable/settable_spec.rb +544 -0
- data/spec/mongoid/persistable/unsettable_spec.rb +171 -0
- data/spec/mongoid/persistable/updatable_spec.rb +760 -0
- data/spec/mongoid/persistable/upsertable_spec.rb +122 -0
- data/spec/mongoid/persistable_spec.rb +321 -0
- data/spec/mongoid/persistence_context_spec.rb +745 -0
- data/spec/mongoid/positional_spec.rb +223 -0
- data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
- data/spec/mongoid/query_cache_spec.rb +870 -0
- data/spec/mongoid/relations/proxy_spec.rb +125 -47
- data/spec/mongoid/reloadable_spec.rb +665 -0
- data/spec/mongoid/scopable_spec.rb +1234 -0
- data/spec/mongoid/selectable_spec.rb +136 -0
- data/spec/mongoid/serializable_spec.rb +963 -0
- data/spec/mongoid/shardable_models.rb +61 -0
- data/spec/mongoid/shardable_spec.rb +204 -0
- data/spec/mongoid/stateful_spec.rb +157 -0
- data/spec/mongoid/tasks/database_rake_spec.rb +287 -0
- data/spec/mongoid/tasks/database_spec.rb +181 -0
- data/spec/mongoid/threaded_spec.rb +88 -78
- data/spec/mongoid/timestamps/created/short_spec.rb +9 -7
- data/spec/mongoid/timestamps/created_spec.rb +8 -6
- data/spec/mongoid/timestamps/timeless_spec.rb +29 -10
- data/spec/mongoid/timestamps/updated/short_spec.rb +16 -14
- data/spec/mongoid/timestamps/updated_spec.rb +14 -16
- data/spec/mongoid/timestamps_spec.rb +406 -18
- data/spec/mongoid/timestamps_spec_models.rb +67 -0
- data/spec/mongoid/touchable_spec.rb +704 -0
- data/spec/mongoid/touchable_spec_models.rb +57 -0
- data/spec/mongoid/traversable_spec.rb +1410 -0
- data/spec/mongoid/validatable/associated_spec.rb +208 -0
- data/spec/mongoid/validatable/format_spec.rb +85 -0
- data/spec/mongoid/validatable/length_spec.rb +225 -0
- data/spec/mongoid/validatable/numericality_spec.rb +32 -0
- data/spec/mongoid/validatable/presence_spec.rb +592 -0
- data/spec/mongoid/validatable/uniqueness_spec.rb +2504 -0
- data/spec/mongoid/validatable_spec.rb +327 -0
- data/spec/mongoid/warnings_spec.rb +35 -0
- data/spec/mongoid_spec.rb +20 -20
- data/spec/rails/controller_extension/controller_runtime_spec.rb +112 -0
- data/spec/rails/mongoid_spec.rb +37 -354
- data/spec/shared/LICENSE +20 -0
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/bin/s3-copy +45 -0
- data/spec/shared/bin/s3-upload +69 -0
- data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
- data/spec/shared/lib/mrss/cluster_config.rb +231 -0
- data/spec/shared/lib/mrss/constraints.rb +378 -0
- data/spec/shared/lib/mrss/docker_runner.rb +291 -0
- data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +230 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +120 -0
- data/spec/shared/lib/mrss/session_registry.rb +69 -0
- data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
- data/spec/shared/lib/mrss/utils.rb +15 -0
- data/spec/shared/share/Dockerfile.erb +325 -0
- data/spec/shared/share/haproxy-1.conf +16 -0
- data/spec/shared/share/haproxy-2.conf +17 -0
- data/spec/shared/shlib/config.sh +27 -0
- data/spec/shared/shlib/distro.sh +74 -0
- data/spec/shared/shlib/server.sh +392 -0
- data/spec/shared/shlib/set_env.sh +169 -0
- data/spec/spec_helper.rb +163 -42
- data/spec/support/authorization.rb +15 -0
- data/spec/support/client_registry.rb +9 -0
- data/spec/support/constraints.rb +77 -0
- data/spec/support/expectations.rb +32 -0
- data/spec/support/helpers.rb +11 -0
- data/spec/support/macros.rb +81 -0
- data/spec/support/models/account.rb +38 -0
- data/spec/support/models/acolyte.rb +19 -0
- data/spec/support/models/actor.rb +20 -0
- data/spec/support/models/actress.rb +4 -0
- data/spec/support/models/address.rb +85 -0
- data/spec/support/models/address_component.rb +7 -0
- data/spec/support/models/address_number.rb +8 -0
- data/spec/support/models/agency.rb +7 -0
- data/spec/support/models/agent.rb +18 -0
- data/spec/support/models/album.rb +20 -0
- data/spec/support/models/alert.rb +9 -0
- data/spec/support/models/animal.rb +28 -0
- data/spec/support/models/answer.rb +8 -0
- data/spec/support/models/appointment.rb +9 -0
- data/spec/support/models/armrest.rb +9 -0
- data/spec/support/models/array_field.rb +7 -0
- data/spec/support/models/article.rb +14 -0
- data/spec/support/models/artist.rb +91 -0
- data/spec/support/models/artwork.rb +6 -0
- data/spec/support/models/audible_sound.rb +3 -0
- data/spec/support/models/audio.rb +7 -0
- data/spec/support/models/augmentation.rb +25 -0
- data/spec/support/models/author.rb +8 -0
- data/spec/support/models/baby.rb +6 -0
- data/spec/support/models/band.rb +40 -0
- data/spec/support/models/bar.rb +12 -0
- data/spec/support/models/basic.rb +8 -0
- data/spec/support/models/bed.rb +3 -0
- data/spec/support/models/big_palette.rb +4 -0
- data/spec/support/models/birthday.rb +15 -0
- data/spec/support/models/bolt.rb +7 -0
- data/spec/support/models/bomb.rb +6 -0
- data/spec/support/models/book.rb +18 -0
- data/spec/support/models/breed.rb +6 -0
- data/spec/support/models/browser.rb +8 -0
- data/spec/support/models/building.rb +8 -0
- data/spec/support/models/building_address.rb +9 -0
- data/spec/support/models/bus.rb +9 -0
- data/spec/support/models/business.rb +7 -0
- data/spec/support/models/callback_test.rb +11 -0
- data/spec/support/models/canvas.rb +27 -0
- data/spec/support/models/car.rb +3 -0
- data/spec/support/models/cat.rb +10 -0
- data/spec/support/models/catalog.rb +24 -0
- data/spec/support/models/category.rb +10 -0
- data/spec/support/models/child.rb +6 -0
- data/spec/support/models/child_doc.rb +24 -0
- data/spec/support/models/church.rb +8 -0
- data/spec/support/models/circle.rb +5 -0
- data/spec/support/models/circuit.rb +6 -0
- data/spec/support/models/circus.rb +12 -0
- data/spec/support/models/code.rb +15 -0
- data/spec/support/models/coding/pull_request.rb +11 -0
- data/spec/support/models/coding.rb +3 -0
- data/spec/support/models/comment.rb +18 -0
- data/spec/support/models/company.rb +7 -0
- data/spec/support/models/consumption_period.rb +9 -0
- data/spec/support/models/contextable_item.rb +7 -0
- data/spec/support/models/contractor.rb +7 -0
- data/spec/support/models/cookie.rb +8 -0
- data/spec/support/models/country_code.rb +12 -0
- data/spec/support/models/courier_job.rb +6 -0
- data/spec/support/models/crate.rb +12 -0
- data/spec/support/models/customer.rb +10 -0
- data/spec/support/models/customer_address.rb +11 -0
- data/spec/support/models/deed.rb +7 -0
- data/spec/support/models/definition.rb +11 -0
- data/spec/support/models/delegating_patient.rb +15 -0
- data/spec/support/models/description.rb +13 -0
- data/spec/support/models/dictionary.rb +18 -0
- data/spec/support/models/division.rb +12 -0
- data/spec/support/models/doctor.rb +14 -0
- data/spec/support/models/dog.rb +9 -0
- data/spec/support/models/dokument.rb +8 -0
- data/spec/support/models/draft.rb +11 -0
- data/spec/support/models/dragon.rb +6 -0
- data/spec/support/models/driver.rb +9 -0
- data/spec/support/models/drug.rb +8 -0
- data/spec/support/models/dungeon.rb +6 -0
- data/spec/support/models/edit.rb +7 -0
- data/spec/support/models/email.rb +8 -0
- data/spec/support/models/employer.rb +7 -0
- data/spec/support/models/entry.rb +8 -0
- data/spec/support/models/eraser.rb +3 -0
- data/spec/support/models/even.rb +9 -0
- data/spec/support/models/event.rb +24 -0
- data/spec/support/models/exhibition.rb +6 -0
- data/spec/support/models/exhibitor.rb +8 -0
- data/spec/support/models/explosion.rb +6 -0
- data/spec/support/models/eye.rb +11 -0
- data/spec/support/models/eye_bowl.rb +11 -0
- data/spec/support/models/face.rb +10 -0
- data/spec/support/models/fanatic.rb +8 -0
- data/spec/support/models/favorite.rb +8 -0
- data/spec/support/models/filesystem.rb +7 -0
- data/spec/support/models/fire_hydrant.rb +8 -0
- data/spec/support/models/firefox.rb +6 -0
- data/spec/support/models/fish.rb +9 -0
- data/spec/support/models/folder.rb +9 -0
- data/spec/support/models/folder_item.rb +11 -0
- data/spec/support/models/fruits.rb +36 -0
- data/spec/support/models/game.rb +21 -0
- data/spec/support/models/ghost.rb +9 -0
- data/spec/support/models/guitar.rb +4 -0
- data/spec/support/models/hole.rb +12 -0
- data/spec/support/models/home.rb +6 -0
- data/spec/support/models/house.rb +8 -0
- data/spec/support/models/html_writer.rb +5 -0
- data/spec/support/models/id_key.rb +8 -0
- data/spec/support/models/idnodef.rb +7 -0
- data/spec/support/models/image.rb +24 -0
- data/spec/support/models/implant.rb +27 -0
- data/spec/support/models/instrument.rb +8 -0
- data/spec/support/models/item.rb +10 -0
- data/spec/support/models/jar.rb +9 -0
- data/spec/support/models/kaleidoscope.rb +8 -0
- data/spec/support/models/kangaroo.rb +6 -0
- data/spec/support/models/label.rb +52 -0
- data/spec/support/models/language.rb +7 -0
- data/spec/support/models/lat_lng.rb +17 -0
- data/spec/support/models/league.rb +13 -0
- data/spec/support/models/learner.rb +4 -0
- data/spec/support/models/line_item.rb +8 -0
- data/spec/support/models/location.rb +10 -0
- data/spec/support/models/login.rb +10 -0
- data/spec/support/models/manufacturer.rb +9 -0
- data/spec/support/models/meat.rb +6 -0
- data/spec/support/models/membership.rb +7 -0
- data/spec/support/models/message.rb +13 -0
- data/spec/support/models/minim.rb +6 -0
- data/spec/support/models/mixed_drink.rb +6 -0
- data/spec/support/models/mop.rb +24 -0
- data/spec/support/models/movie.rb +15 -0
- data/spec/support/models/my_hash.rb +4 -0
- data/spec/support/models/name.rb +26 -0
- data/spec/support/models/name_only.rb +8 -0
- data/spec/support/models/node.rb +7 -0
- data/spec/support/models/note.rb +19 -0
- data/spec/support/models/nut.rb +7 -0
- data/spec/support/models/odd.rb +9 -0
- data/spec/support/models/order.rb +12 -0
- data/spec/support/models/ordered_post.rb +13 -0
- data/spec/support/models/ordered_preference.rb +8 -0
- data/spec/support/models/oscar.rb +16 -0
- data/spec/support/models/other_owner_object.rb +4 -0
- data/spec/support/models/override.rb +18 -0
- data/spec/support/models/ownable.rb +8 -0
- data/spec/support/models/owner.rb +10 -0
- data/spec/support/models/pack.rb +5 -0
- data/spec/support/models/page.rb +18 -0
- data/spec/support/models/page_question.rb +6 -0
- data/spec/support/models/palette.rb +9 -0
- data/spec/support/models/parent.rb +7 -0
- data/spec/support/models/parent_doc.rb +8 -0
- data/spec/support/models/passport.rb +22 -0
- data/spec/support/models/patient.rb +11 -0
- data/spec/support/models/pdf_writer.rb +5 -0
- data/spec/support/models/pencil.rb +3 -0
- data/spec/support/models/person.rb +231 -0
- data/spec/support/models/pet.rb +25 -0
- data/spec/support/models/pet_owner.rb +8 -0
- data/spec/support/models/phone.rb +13 -0
- data/spec/support/models/piano.rb +4 -0
- data/spec/support/models/pizza.rb +9 -0
- data/spec/support/models/player.rb +39 -0
- data/spec/support/models/post.rb +52 -0
- data/spec/support/models/post_genre.rb +8 -0
- data/spec/support/models/powerup.rb +25 -0
- data/spec/support/models/preference.rb +11 -0
- data/spec/support/models/princess.rb +12 -0
- data/spec/support/models/product.rb +19 -0
- data/spec/support/models/profile.rb +17 -0
- data/spec/support/models/pronunciation.rb +7 -0
- data/spec/support/models/pub.rb +8 -0
- data/spec/support/models/publication/encyclopedia.rb +11 -0
- data/spec/support/models/publication/review.rb +13 -0
- data/spec/support/models/publication.rb +4 -0
- data/spec/support/models/purchase.rb +6 -0
- data/spec/support/models/purchased_item.rb +10 -0
- data/spec/support/models/question.rb +10 -0
- data/spec/support/models/quiz.rb +9 -0
- data/spec/support/models/rating.rb +10 -0
- data/spec/support/models/record.rb +54 -0
- data/spec/support/models/registry.rb +7 -0
- data/spec/support/models/role.rb +9 -0
- data/spec/support/models/root_category.rb +6 -0
- data/spec/support/models/sandwich.rb +11 -0
- data/spec/support/models/scheduler.rb +9 -0
- data/spec/support/models/school.rb +14 -0
- data/spec/support/models/scribe.rb +7 -0
- data/spec/support/models/sealer.rb +7 -0
- data/spec/support/models/seat.rb +24 -0
- data/spec/support/models/seo.rb +9 -0
- data/spec/support/models/series.rb +7 -0
- data/spec/support/models/server.rb +15 -0
- data/spec/support/models/service.rb +24 -0
- data/spec/support/models/shape.rb +14 -0
- data/spec/support/models/shelf.rb +7 -0
- data/spec/support/models/shield.rb +18 -0
- data/spec/support/models/shipment_address.rb +5 -0
- data/spec/support/models/shipping_container.rb +7 -0
- data/spec/support/models/shipping_pack.rb +5 -0
- data/spec/support/models/shirt.rb +11 -0
- data/spec/support/models/shop.rb +8 -0
- data/spec/support/models/short_agent.rb +6 -0
- data/spec/support/models/short_quiz.rb +7 -0
- data/spec/support/models/simple.rb +7 -0
- data/spec/support/models/slave.rb +8 -0
- data/spec/support/models/song.rb +10 -0
- data/spec/support/models/sound.rb +7 -0
- data/spec/support/models/spacer.rb +7 -0
- data/spec/support/models/square.rb +6 -0
- data/spec/support/models/staff.rb +9 -0
- data/spec/support/models/store_as_dup_test1.rb +7 -0
- data/spec/support/models/store_as_dup_test2.rb +7 -0
- data/spec/support/models/store_as_dup_test3.rb +7 -0
- data/spec/support/models/store_as_dup_test4.rb +7 -0
- data/spec/support/models/strategy.rb +5 -0
- data/spec/support/models/student.rb +14 -0
- data/spec/support/models/sub_item.rb +5 -0
- data/spec/support/models/subscription.rb +7 -0
- data/spec/support/models/survey.rb +7 -0
- data/spec/support/models/symptom.rb +8 -0
- data/spec/support/models/system_role.rb +7 -0
- data/spec/support/models/tag.rb +10 -0
- data/spec/support/models/target.rb +7 -0
- data/spec/support/models/template.rb +7 -0
- data/spec/support/models/thing.rb +11 -0
- data/spec/support/models/threadlocker.rb +7 -0
- data/spec/support/models/title.rb +5 -0
- data/spec/support/models/tool.rb +10 -0
- data/spec/support/models/topping.rb +7 -0
- data/spec/support/models/toy.rb +9 -0
- data/spec/support/models/track.rb +40 -0
- data/spec/support/models/translation.rb +7 -0
- data/spec/support/models/tree.rb +11 -0
- data/spec/support/models/truck.rb +7 -0
- data/spec/support/models/updatable.rb +7 -0
- data/spec/support/models/user.rb +23 -0
- data/spec/support/models/user_account.rb +12 -0
- data/spec/support/models/validation_callback.rb +12 -0
- data/spec/support/models/vehicle.rb +18 -0
- data/spec/support/models/version.rb +7 -0
- data/spec/support/models/vertex.rb +8 -0
- data/spec/support/models/vet_visit.rb +7 -0
- data/spec/support/models/video.rb +15 -0
- data/spec/support/models/video_game.rb +3 -0
- data/spec/support/models/washer.rb +7 -0
- data/spec/support/models/weapon.rb +25 -0
- data/spec/support/models/wiki_page.rb +17 -0
- data/spec/support/models/word.rb +17 -0
- data/spec/support/models/word_origin.rb +13 -0
- data/spec/support/models/writer.rb +13 -0
- data/spec/support/schema_maps/schema_map_aws.json +17 -0
- data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_azure.json +17 -0
- data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_gcp.json +17 -0
- data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_kmip.json +17 -0
- data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_local.json +18 -0
- data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
- data/spec/support/shared/time.rb +53 -0
- data/spec/support/spec_config.rb +64 -0
- data.tar.gz.sig +0 -0
- metadata +1582 -912
- metadata.gz.sig +0 -0
- data/lib/mongoid/atomic/positionable.rb +0 -73
- data/lib/mongoid/callbacks.rb +0 -314
- data/lib/mongoid/components.rb +0 -93
- data/lib/mongoid/config/inflections.rb +0 -6
- data/lib/mongoid/config/validators/session.rb +0 -140
- data/lib/mongoid/contextual/eager.rb +0 -158
- data/lib/mongoid/contextual/find_and_modify.rb +0 -69
- data/lib/mongoid/criterion/findable.rb +0 -179
- data/lib/mongoid/criterion/inspection.rb +0 -25
- data/lib/mongoid/criterion/marshalable.rb +0 -48
- data/lib/mongoid/criterion/modifiable.rb +0 -189
- data/lib/mongoid/criterion/scoping.rb +0 -158
- data/lib/mongoid/dirty.rb +0 -376
- data/lib/mongoid/errors/eager_load.rb +0 -22
- data/lib/mongoid/errors/mixed_session_configuration.rb +0 -28
- data/lib/mongoid/errors/no_default_session.rb +0 -23
- data/lib/mongoid/errors/no_session_config.rb +0 -22
- data/lib/mongoid/errors/no_session_database.rb +0 -27
- data/lib/mongoid/errors/no_session_hosts.rb +0 -27
- data/lib/mongoid/errors/no_sessions_config.rb +0 -20
- data/lib/mongoid/errors/versioning_not_on_root.rb +0 -23
- data/lib/mongoid/finders.rb +0 -130
- data/lib/mongoid/hierarchy.rb +0 -188
- data/lib/mongoid/identity_map.rb +0 -163
- data/lib/mongoid/indexes/validators/options.rb +0 -102
- data/lib/mongoid/indexes.rb +0 -154
- data/lib/mongoid/inspection.rb +0 -55
- data/lib/mongoid/json.rb +0 -16
- data/lib/mongoid/matchers/all.rb +0 -27
- data/lib/mongoid/matchers/and.rb +0 -30
- data/lib/mongoid/matchers/default.rb +0 -72
- data/lib/mongoid/matchers/exists.rb +0 -23
- data/lib/mongoid/matchers/gt.rb +0 -21
- data/lib/mongoid/matchers/gte.rb +0 -21
- data/lib/mongoid/matchers/in.rb +0 -24
- data/lib/mongoid/matchers/lt.rb +0 -21
- data/lib/mongoid/matchers/lte.rb +0 -21
- data/lib/mongoid/matchers/ne.rb +0 -21
- data/lib/mongoid/matchers/nin.rb +0 -21
- data/lib/mongoid/matchers/or.rb +0 -33
- data/lib/mongoid/matchers/size.rb +0 -21
- data/lib/mongoid/matchers/strategies.rb +0 -97
- data/lib/mongoid/matchers.rb +0 -32
- data/lib/mongoid/multi_parameter_attributes.rb +0 -105
- data/lib/mongoid/nested_attributes.rb +0 -78
- data/lib/mongoid/observer.rb +0 -192
- data/lib/mongoid/paranoia.rb +0 -137
- data/lib/mongoid/persistence/atomic/add_to_set.rb +0 -47
- data/lib/mongoid/persistence/atomic/bit.rb +0 -35
- data/lib/mongoid/persistence/atomic/inc.rb +0 -45
- data/lib/mongoid/persistence/atomic/operation.rb +0 -154
- data/lib/mongoid/persistence/atomic/pop.rb +0 -32
- data/lib/mongoid/persistence/atomic/pull.rb +0 -32
- data/lib/mongoid/persistence/atomic/pull_all.rb +0 -32
- data/lib/mongoid/persistence/atomic/push.rb +0 -25
- data/lib/mongoid/persistence/atomic/push_all.rb +0 -25
- data/lib/mongoid/persistence/atomic/rename.rb +0 -30
- data/lib/mongoid/persistence/atomic/sets.rb +0 -28
- data/lib/mongoid/persistence/atomic/unset.rb +0 -27
- data/lib/mongoid/persistence/atomic.rb +0 -231
- data/lib/mongoid/persistence/deletion.rb +0 -32
- data/lib/mongoid/persistence/insertion.rb +0 -38
- data/lib/mongoid/persistence/modification.rb +0 -35
- data/lib/mongoid/persistence/operations/embedded/insert.rb +0 -46
- data/lib/mongoid/persistence/operations/embedded/remove.rb +0 -43
- data/lib/mongoid/persistence/operations/insert.rb +0 -34
- data/lib/mongoid/persistence/operations/remove.rb +0 -33
- data/lib/mongoid/persistence/operations/update.rb +0 -59
- data/lib/mongoid/persistence/operations/upsert.rb +0 -28
- data/lib/mongoid/persistence/operations.rb +0 -214
- data/lib/mongoid/persistence/upsertion.rb +0 -31
- data/lib/mongoid/persistence.rb +0 -352
- data/lib/mongoid/railties/document.rb +0 -12
- data/lib/mongoid/relations/accessors.rb +0 -299
- data/lib/mongoid/relations/auto_save.rb +0 -107
- data/lib/mongoid/relations/binding.rb +0 -241
- data/lib/mongoid/relations/bindings/embedded/in.rb +0 -63
- data/lib/mongoid/relations/bindings/embedded/many.rb +0 -52
- data/lib/mongoid/relations/bindings/embedded/one.rb +0 -55
- data/lib/mongoid/relations/bindings/referenced/in.rb +0 -70
- data/lib/mongoid/relations/bindings/referenced/many.rb +0 -42
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +0 -67
- data/lib/mongoid/relations/bindings/referenced/one.rb +0 -44
- data/lib/mongoid/relations/bindings.rb +0 -9
- data/lib/mongoid/relations/builder.rb +0 -57
- data/lib/mongoid/relations/builders/embedded/in.rb +0 -29
- data/lib/mongoid/relations/builders/embedded/many.rb +0 -36
- data/lib/mongoid/relations/builders/embedded/one.rb +0 -30
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +0 -177
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +0 -127
- data/lib/mongoid/relations/builders/referenced/in.rb +0 -26
- data/lib/mongoid/relations/builders/referenced/many.rb +0 -27
- data/lib/mongoid/relations/builders/referenced/many_to_many.rb +0 -40
- data/lib/mongoid/relations/builders/referenced/one.rb +0 -26
- data/lib/mongoid/relations/builders.rb +0 -104
- data/lib/mongoid/relations/cascading/delete.rb +0 -44
- data/lib/mongoid/relations/cascading/destroy.rb +0 -43
- data/lib/mongoid/relations/cascading/nullify.rb +0 -35
- data/lib/mongoid/relations/cascading/restrict.rb +0 -39
- data/lib/mongoid/relations/cascading.rb +0 -58
- data/lib/mongoid/relations/constraint.rb +0 -49
- data/lib/mongoid/relations/conversions.rb +0 -34
- data/lib/mongoid/relations/counter_cache.rb +0 -107
- data/lib/mongoid/relations/cyclic.rb +0 -107
- data/lib/mongoid/relations/embedded/batchable.rb +0 -356
- data/lib/mongoid/relations/embedded/in.rb +0 -231
- data/lib/mongoid/relations/embedded/many.rb +0 -659
- data/lib/mongoid/relations/embedded/one.rb +0 -223
- data/lib/mongoid/relations/macros.rb +0 -359
- data/lib/mongoid/relations/many.rb +0 -217
- data/lib/mongoid/relations/marshalable.rb +0 -32
- data/lib/mongoid/relations/metadata.rb +0 -1227
- data/lib/mongoid/relations/nested_builder.rb +0 -74
- data/lib/mongoid/relations/one.rb +0 -60
- data/lib/mongoid/relations/options.rb +0 -48
- data/lib/mongoid/relations/polymorphic.rb +0 -40
- data/lib/mongoid/relations/proxy.rb +0 -264
- data/lib/mongoid/relations/referenced/in.rb +0 -314
- data/lib/mongoid/relations/referenced/many.rb +0 -789
- data/lib/mongoid/relations/referenced/many_to_many.rb +0 -495
- data/lib/mongoid/relations/referenced/one.rb +0 -297
- data/lib/mongoid/relations/reflections.rb +0 -62
- data/lib/mongoid/relations/synchronization.rb +0 -169
- data/lib/mongoid/relations/targets/enumerable.rb +0 -473
- data/lib/mongoid/relations/targets.rb +0 -2
- data/lib/mongoid/relations/touchable.rb +0 -61
- data/lib/mongoid/relations.rb +0 -162
- data/lib/mongoid/reloading.rb +0 -92
- data/lib/mongoid/scoping.rb +0 -356
- data/lib/mongoid/serialization.rb +0 -161
- data/lib/mongoid/sessions/factory.rb +0 -129
- data/lib/mongoid/sessions/mongo_uri.rb +0 -93
- data/lib/mongoid/sessions/validators/storage.rb +0 -49
- data/lib/mongoid/sessions/validators.rb +0 -2
- data/lib/mongoid/sessions.rb +0 -433
- data/lib/mongoid/sharding.rb +0 -61
- data/lib/mongoid/state.rb +0 -97
- data/lib/mongoid/unit_of_work.rb +0 -61
- data/lib/mongoid/validations/associated.rb +0 -46
- data/lib/mongoid/validations/format.rb +0 -20
- data/lib/mongoid/validations/length.rb +0 -20
- data/lib/mongoid/validations/localizable.rb +0 -30
- data/lib/mongoid/validations/macros.rb +0 -93
- data/lib/mongoid/validations/presence.rb +0 -86
- data/lib/mongoid/validations/queryable.rb +0 -31
- data/lib/mongoid/validations/uniqueness.rb +0 -330
- data/lib/mongoid/validations.rb +0 -166
- data/lib/mongoid/versioning.rb +0 -217
- data/lib/rack/mongoid/middleware/identity_map.rb +0 -39
- data/lib/rack/mongoid.rb +0 -2
- data/lib/rails/generators/mongoid/observer/observer_generator.rb +0 -17
- data/lib/rails/generators/mongoid/observer/templates/observer.rb.tt +0 -4
- data/lib/support/ruby_version.rb +0 -26
- data/spec/app/models/account.rb +0 -32
- data/spec/app/models/acolyte.rb +0 -16
- data/spec/app/models/actor.rb +0 -19
- data/spec/app/models/actor_observer.rb +0 -15
- data/spec/app/models/actress.rb +0 -2
- data/spec/app/models/address.rb +0 -72
- data/spec/app/models/address_component.rb +0 -5
- data/spec/app/models/address_number.rb +0 -6
- data/spec/app/models/agency.rb +0 -5
- data/spec/app/models/agent.rb +0 -12
- data/spec/app/models/album.rb +0 -14
- data/spec/app/models/alert.rb +0 -5
- data/spec/app/models/animal.rb +0 -25
- data/spec/app/models/answer.rb +0 -4
- data/spec/app/models/appointment.rb +0 -7
- data/spec/app/models/article.rb +0 -13
- data/spec/app/models/artist.rb +0 -66
- data/spec/app/models/artwork.rb +0 -4
- data/spec/app/models/augmentation.rb +0 -11
- data/spec/app/models/author.rb +0 -6
- data/spec/app/models/band.rb +0 -25
- data/spec/app/models/bar.rb +0 -9
- data/spec/app/models/basic.rb +0 -6
- data/spec/app/models/bed.rb +0 -1
- data/spec/app/models/big_palette.rb +0 -2
- data/spec/app/models/birthday.rb +0 -13
- data/spec/app/models/book.rb +0 -12
- data/spec/app/models/breed.rb +0 -4
- data/spec/app/models/browser.rb +0 -6
- data/spec/app/models/building.rb +0 -7
- data/spec/app/models/building_address.rb +0 -7
- data/spec/app/models/bus.rb +0 -7
- data/spec/app/models/business.rb +0 -5
- data/spec/app/models/callback_recorder.rb +0 -25
- data/spec/app/models/callback_test.rb +0 -9
- data/spec/app/models/canvas.rb +0 -25
- data/spec/app/models/car.rb +0 -1
- data/spec/app/models/cat.rb +0 -8
- data/spec/app/models/category.rb +0 -8
- data/spec/app/models/child.rb +0 -4
- data/spec/app/models/child_doc.rb +0 -22
- data/spec/app/models/church.rb +0 -4
- data/spec/app/models/circle.rb +0 -3
- data/spec/app/models/circuit.rb +0 -4
- data/spec/app/models/circus.rb +0 -7
- data/spec/app/models/code.rb +0 -5
- data/spec/app/models/comment.rb +0 -16
- data/spec/app/models/contractor.rb +0 -7
- data/spec/app/models/cookie.rb +0 -6
- data/spec/app/models/country_code.rb +0 -8
- data/spec/app/models/definition.rb +0 -8
- data/spec/app/models/description.rb +0 -11
- data/spec/app/models/dictionary.rb +0 -10
- data/spec/app/models/division.rb +0 -10
- data/spec/app/models/doctor.rb +0 -12
- data/spec/app/models/dog.rb +0 -7
- data/spec/app/models/dokument.rb +0 -5
- data/spec/app/models/driver.rb +0 -7
- data/spec/app/models/drug.rb +0 -8
- data/spec/app/models/email.rb +0 -6
- data/spec/app/models/employer.rb +0 -5
- data/spec/app/models/entry.rb +0 -6
- data/spec/app/models/eraser.rb +0 -1
- data/spec/app/models/event.rb +0 -22
- data/spec/app/models/exhibition.rb +0 -4
- data/spec/app/models/exhibitor.rb +0 -5
- data/spec/app/models/eye.rb +0 -9
- data/spec/app/models/eye_bowl.rb +0 -9
- data/spec/app/models/face.rb +0 -8
- data/spec/app/models/favorite.rb +0 -6
- data/spec/app/models/filesystem.rb +0 -4
- data/spec/app/models/fire_hydrant.rb +0 -6
- data/spec/app/models/firefox.rb +0 -4
- data/spec/app/models/fish.rb +0 -8
- data/spec/app/models/folder.rb +0 -7
- data/spec/app/models/folder_item.rb +0 -9
- data/spec/app/models/fruits.rb +0 -28
- data/spec/app/models/game.rb +0 -21
- data/spec/app/models/ghost.rb +0 -7
- data/spec/app/models/home.rb +0 -4
- data/spec/app/models/house.rb +0 -8
- data/spec/app/models/html_writer.rb +0 -3
- data/spec/app/models/image.rb +0 -22
- data/spec/app/models/implant.rb +0 -16
- data/spec/app/models/item.rb +0 -12
- data/spec/app/models/jar.rb +0 -7
- data/spec/app/models/label.rb +0 -40
- data/spec/app/models/language.rb +0 -5
- data/spec/app/models/lat_lng.rb +0 -15
- data/spec/app/models/league.rb +0 -11
- data/spec/app/models/learner.rb +0 -2
- data/spec/app/models/line_item.rb +0 -6
- data/spec/app/models/location.rb +0 -8
- data/spec/app/models/login.rb +0 -8
- data/spec/app/models/manufacturer.rb +0 -7
- data/spec/app/models/meat.rb +0 -4
- data/spec/app/models/membership.rb +0 -4
- data/spec/app/models/mixed_drink.rb +0 -4
- data/spec/app/models/movie.rb +0 -12
- data/spec/app/models/my_hash.rb +0 -2
- data/spec/app/models/name.rb +0 -23
- data/spec/app/models/node.rb +0 -5
- data/spec/app/models/note.rb +0 -12
- data/spec/app/models/ordered_post.rb +0 -6
- data/spec/app/models/ordered_preference.rb +0 -6
- data/spec/app/models/oscar.rb +0 -15
- data/spec/app/models/override.rb +0 -16
- data/spec/app/models/ownable.rb +0 -6
- data/spec/app/models/owner.rb +0 -6
- data/spec/app/models/pack.rb +0 -3
- data/spec/app/models/page.rb +0 -5
- data/spec/app/models/page_question.rb +0 -4
- data/spec/app/models/palette.rb +0 -7
- data/spec/app/models/paranoid_phone.rb +0 -25
- data/spec/app/models/paranoid_post.rb +0 -36
- data/spec/app/models/parent.rb +0 -5
- data/spec/app/models/parent_doc.rb +0 -6
- data/spec/app/models/passport.rb +0 -5
- data/spec/app/models/patient.rb +0 -9
- data/spec/app/models/pdf_writer.rb +0 -3
- data/spec/app/models/pencil.rb +0 -1
- data/spec/app/models/person.rb +0 -201
- data/spec/app/models/pet.rb +0 -23
- data/spec/app/models/pet_owner.rb +0 -6
- data/spec/app/models/phone.rb +0 -11
- data/spec/app/models/phone_observer.rb +0 -6
- data/spec/app/models/pizza.rb +0 -7
- data/spec/app/models/player.rb +0 -35
- data/spec/app/models/post.rb +0 -43
- data/spec/app/models/powerup.rb +0 -11
- data/spec/app/models/preference.rb +0 -9
- data/spec/app/models/princess.rb +0 -8
- data/spec/app/models/product.rb +0 -17
- data/spec/app/models/profile.rb +0 -5
- data/spec/app/models/pronunciation.rb +0 -5
- data/spec/app/models/purchase.rb +0 -4
- data/spec/app/models/question.rb +0 -8
- data/spec/app/models/quiz.rb +0 -10
- data/spec/app/models/rating.rb +0 -8
- data/spec/app/models/record.rb +0 -46
- data/spec/app/models/registry.rb +0 -4
- data/spec/app/models/role.rb +0 -7
- data/spec/app/models/root_category.rb +0 -4
- data/spec/app/models/sandwich.rb +0 -4
- data/spec/app/models/scheduler.rb +0 -7
- data/spec/app/models/seo.rb +0 -7
- data/spec/app/models/series.rb +0 -4
- data/spec/app/models/server.rb +0 -13
- data/spec/app/models/service.rb +0 -22
- data/spec/app/models/shape.rb +0 -12
- data/spec/app/models/shelf.rb +0 -5
- data/spec/app/models/shipping_container.rb +0 -5
- data/spec/app/models/shipping_pack.rb +0 -3
- data/spec/app/models/shop.rb +0 -6
- data/spec/app/models/short_agent.rb +0 -4
- data/spec/app/models/short_quiz.rb +0 -5
- data/spec/app/models/slave.rb +0 -6
- data/spec/app/models/song.rb +0 -8
- data/spec/app/models/square.rb +0 -4
- data/spec/app/models/strategy.rb +0 -3
- data/spec/app/models/sub_item.rb +0 -3
- data/spec/app/models/subscription.rb +0 -4
- data/spec/app/models/survey.rb +0 -5
- data/spec/app/models/symptom.rb +0 -6
- data/spec/app/models/tag.rb +0 -8
- data/spec/app/models/target.rb +0 -5
- data/spec/app/models/template.rb +0 -5
- data/spec/app/models/thing.rb +0 -9
- data/spec/app/models/title.rb +0 -4
- data/spec/app/models/tool.rb +0 -8
- data/spec/app/models/topping.rb +0 -5
- data/spec/app/models/track.rb +0 -38
- data/spec/app/models/translation.rb +0 -5
- data/spec/app/models/tree.rb +0 -9
- data/spec/app/models/truck.rb +0 -3
- data/spec/app/models/user.rb +0 -21
- data/spec/app/models/user_account.rb +0 -10
- data/spec/app/models/validation_callback.rb +0 -10
- data/spec/app/models/vehicle.rb +0 -11
- data/spec/app/models/version.rb +0 -5
- data/spec/app/models/vet_visit.rb +0 -5
- data/spec/app/models/video.rb +0 -17
- data/spec/app/models/video_game.rb +0 -1
- data/spec/app/models/weapon.rb +0 -11
- data/spec/app/models/wiki_page.rb +0 -17
- data/spec/app/models/word.rb +0 -12
- data/spec/app/models/word_origin.rb +0 -11
- data/spec/app/models/writer.rb +0 -11
- data/spec/mongoid/atomic/positionable_spec.rb +0 -227
- data/spec/mongoid/attributes/processing_spec.rb +0 -149
- data/spec/mongoid/callbacks_spec.rb +0 -1564
- data/spec/mongoid/components_spec.rb +0 -24
- data/spec/mongoid/contextual/find_and_modify_spec.rb +0 -220
- data/spec/mongoid/criterion/destructive_spec.rb +0 -101
- data/spec/mongoid/criterion/inspection_spec.rb +0 -27
- data/spec/mongoid/criterion/marshalable_spec.rb +0 -28
- data/spec/mongoid/criterion/modifiable_spec.rb +0 -409
- data/spec/mongoid/criterion/modification_spec.rb +0 -402
- data/spec/mongoid/criterion/scoping_spec.rb +0 -391
- data/spec/mongoid/dirty_spec.rb +0 -1508
- data/spec/mongoid/errors/eager_load_spec.rb +0 -29
- data/spec/mongoid/errors/mixed_session_configuration_spec.rb +0 -29
- data/spec/mongoid/errors/no_session_config_spec.rb +0 -29
- data/spec/mongoid/errors/no_session_database_spec.rb +0 -29
- data/spec/mongoid/errors/no_session_hosts_spec.rb +0 -29
- data/spec/mongoid/errors/no_sessions_config_spec.rb +0 -29
- data/spec/mongoid/errors/versioning_not_on_root_spec.rb +0 -29
- data/spec/mongoid/fields/internal/foreign_keys/array_spec.rb +0 -184
- data/spec/mongoid/fields/internal/foreign_keys/object_spec.rb +0 -201
- data/spec/mongoid/finders_spec.rb +0 -321
- data/spec/mongoid/hierarchy_spec.rb +0 -244
- data/spec/mongoid/identity_map_spec.rb +0 -564
- data/spec/mongoid/indexes_spec.rb +0 -404
- data/spec/mongoid/inspection_spec.rb +0 -57
- data/spec/mongoid/json_spec.rb +0 -33
- data/spec/mongoid/matchers/all_spec.rb +0 -31
- data/spec/mongoid/matchers/and_spec.rb +0 -162
- data/spec/mongoid/matchers/default_spec.rb +0 -130
- data/spec/mongoid/matchers/exists_spec.rb +0 -57
- data/spec/mongoid/matchers/gt_spec.rb +0 -74
- data/spec/mongoid/matchers/gte_spec.rb +0 -74
- data/spec/mongoid/matchers/in_spec.rb +0 -25
- data/spec/mongoid/matchers/lt_spec.rb +0 -74
- data/spec/mongoid/matchers/lte_spec.rb +0 -74
- data/spec/mongoid/matchers/ne_spec.rb +0 -25
- data/spec/mongoid/matchers/nin_spec.rb +0 -25
- data/spec/mongoid/matchers/or_spec.rb +0 -106
- data/spec/mongoid/matchers/size_spec.rb +0 -25
- data/spec/mongoid/matchers_spec.rb +0 -532
- data/spec/mongoid/multi_parameter_attributes_spec.rb +0 -128
- data/spec/mongoid/nested_attributes_spec.rb +0 -4945
- data/spec/mongoid/observer_spec.rb +0 -290
- data/spec/mongoid/paranoia_spec.rb +0 -759
- data/spec/mongoid/persistence/atomic/add_to_set_spec.rb +0 -262
- data/spec/mongoid/persistence/atomic/bit_spec.rb +0 -88
- data/spec/mongoid/persistence/atomic/inc_spec.rb +0 -133
- data/spec/mongoid/persistence/atomic/pop_spec.rb +0 -111
- data/spec/mongoid/persistence/atomic/pull_all_spec.rb +0 -77
- data/spec/mongoid/persistence/atomic/pull_spec.rb +0 -80
- data/spec/mongoid/persistence/atomic/push_all_spec.rb +0 -77
- data/spec/mongoid/persistence/atomic/push_spec.rb +0 -77
- data/spec/mongoid/persistence/atomic/rename_spec.rb +0 -42
- data/spec/mongoid/persistence/atomic/sets_spec.rb +0 -154
- data/spec/mongoid/persistence/atomic/unset_spec.rb +0 -65
- data/spec/mongoid/persistence/atomic_spec.rb +0 -216
- data/spec/mongoid/persistence/operations/embedded/insert_spec.rb +0 -191
- data/spec/mongoid/persistence/operations/embedded/remove_spec.rb +0 -8
- data/spec/mongoid/persistence/operations/insert_spec.rb +0 -149
- data/spec/mongoid/persistence/operations/remove_spec.rb +0 -113
- data/spec/mongoid/persistence/operations/update_spec.rb +0 -141
- data/spec/mongoid/persistence/operations/upsert_spec.rb +0 -59
- data/spec/mongoid/persistence/operations_spec.rb +0 -313
- data/spec/mongoid/persistence_spec.rb +0 -2279
- data/spec/mongoid/railties/document_spec.rb +0 -24
- data/spec/mongoid/relations/accessors_spec.rb +0 -844
- data/spec/mongoid/relations/auto_save_spec.rb +0 -261
- data/spec/mongoid/relations/bindings/embedded/in_spec.rb +0 -171
- data/spec/mongoid/relations/bindings/embedded/many_spec.rb +0 -54
- data/spec/mongoid/relations/bindings/embedded/one_spec.rb +0 -77
- data/spec/mongoid/relations/bindings/referenced/in_spec.rb +0 -241
- data/spec/mongoid/relations/bindings/referenced/many_spec.rb +0 -153
- data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +0 -178
- data/spec/mongoid/relations/bindings/referenced/one_spec.rb +0 -131
- data/spec/mongoid/relations/builders/embedded/in_spec.rb +0 -34
- data/spec/mongoid/relations/builders/embedded/many_spec.rb +0 -132
- data/spec/mongoid/relations/builders/embedded/one_spec.rb +0 -99
- data/spec/mongoid/relations/builders/nested_attributes/many_spec.rb +0 -234
- data/spec/mongoid/relations/builders/nested_attributes/one_spec.rb +0 -250
- data/spec/mongoid/relations/builders/referenced/in_spec.rb +0 -241
- data/spec/mongoid/relations/builders/referenced/many_spec.rb +0 -137
- data/spec/mongoid/relations/builders/referenced/many_to_many_spec.rb +0 -178
- data/spec/mongoid/relations/builders/referenced/one_spec.rb +0 -124
- data/spec/mongoid/relations/builders_spec.rb +0 -226
- data/spec/mongoid/relations/cascading/delete_spec.rb +0 -101
- data/spec/mongoid/relations/cascading/destroy_spec.rb +0 -47
- data/spec/mongoid/relations/cascading/nullify_spec.rb +0 -32
- data/spec/mongoid/relations/cascading/restrict_spec.rb +0 -68
- data/spec/mongoid/relations/cascading_spec.rb +0 -355
- data/spec/mongoid/relations/constraint_spec.rb +0 -74
- data/spec/mongoid/relations/conversions_spec.rb +0 -126
- data/spec/mongoid/relations/counter_cache_spec.rb +0 -205
- data/spec/mongoid/relations/cyclic_spec.rb +0 -156
- data/spec/mongoid/relations/embedded/dirty_spec.rb +0 -65
- data/spec/mongoid/relations/embedded/in_spec.rb +0 -580
- data/spec/mongoid/relations/embedded/many_spec.rb +0 -3841
- data/spec/mongoid/relations/embedded/one_spec.rb +0 -1055
- data/spec/mongoid/relations/macros_spec.rb +0 -625
- data/spec/mongoid/relations/metadata_spec.rb +0 -2030
- data/spec/mongoid/relations/options_spec.rb +0 -35
- data/spec/mongoid/relations/polymorphic_spec.rb +0 -132
- data/spec/mongoid/relations/referenced/in_spec.rb +0 -1501
- data/spec/mongoid/relations/referenced/many_spec.rb +0 -3632
- data/spec/mongoid/relations/referenced/many_to_many_spec.rb +0 -3561
- data/spec/mongoid/relations/referenced/one_spec.rb +0 -1331
- data/spec/mongoid/relations/reflections_spec.rb +0 -101
- data/spec/mongoid/relations/synchronization_spec.rb +0 -453
- data/spec/mongoid/relations/targets/enumerable_spec.rb +0 -1710
- data/spec/mongoid/relations_spec.rb +0 -188
- data/spec/mongoid/reloading_spec.rb +0 -305
- data/spec/mongoid/scoping_spec.rb +0 -978
- data/spec/mongoid/serialization_spec.rb +0 -833
- data/spec/mongoid/sessions/factory_spec.rb +0 -312
- data/spec/mongoid/sessions/mongo_uri_spec.rb +0 -103
- data/spec/mongoid/sessions_spec.rb +0 -1111
- data/spec/mongoid/sharding_spec.rb +0 -61
- data/spec/mongoid/state_spec.rb +0 -102
- data/spec/mongoid/unit_of_work_spec.rb +0 -196
- data/spec/mongoid/validations/associated_spec.rb +0 -183
- data/spec/mongoid/validations/format_spec.rb +0 -83
- data/spec/mongoid/validations/length_spec.rb +0 -223
- data/spec/mongoid/validations/numericality_spec.rb +0 -30
- data/spec/mongoid/validations/presence_spec.rb +0 -592
- data/spec/mongoid/validations/uniqueness_spec.rb +0 -2399
- data/spec/mongoid/validations_spec.rb +0 -309
- data/spec/mongoid/versioning_spec.rb +0 -540
- data/spec/rack/mongoid/middleware/identity_map_spec.rb +0 -72
|
@@ -0,0 +1,5000 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require_relative '../association/referenced/has_many_models'
|
|
5
|
+
require_relative '../association/referenced/has_and_belongs_to_many_models'
|
|
6
|
+
require_relative './nested_spec_models'
|
|
7
|
+
|
|
8
|
+
describe Mongoid::Attributes::Nested do
|
|
9
|
+
|
|
10
|
+
describe ".accepts_nested_attributes_for" do
|
|
11
|
+
|
|
12
|
+
context "when the autosave option is not defined" do
|
|
13
|
+
|
|
14
|
+
let(:person) do
|
|
15
|
+
Person.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
before do
|
|
19
|
+
Person.accepts_nested_attributes_for :favorites
|
|
20
|
+
Person.accepts_nested_attributes_for :children
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
after do
|
|
24
|
+
Person.send(:undef_method, :favorites_attributes=)
|
|
25
|
+
Person.send(:undef_method, :children_attributes=)
|
|
26
|
+
Person.nested_attributes.clear
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "adds a method for handling the attributes" do
|
|
30
|
+
expect(person).to respond_to(:favorites_attributes=)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "does not autosave if the association is embedded" do
|
|
34
|
+
expect(person).not_to respond_to(:autosave_documents_for_favorites)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "autosaves if the association is not embedded" do
|
|
38
|
+
expect(person).to respond_to(:autosave_documents_for_children)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "adds the method name to the nested attributes list" do
|
|
42
|
+
expect(Person.nested_attributes).to eq({
|
|
43
|
+
"favorites_attributes" => "favorites_attributes=",
|
|
44
|
+
"children_attributes" => "children_attributes="
|
|
45
|
+
})
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "when autosave is explicitly false" do
|
|
50
|
+
|
|
51
|
+
before do
|
|
52
|
+
Account.accepts_nested_attributes_for :alerts
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
after do
|
|
56
|
+
Account.send(:undef_method, :alerts_attributes=)
|
|
57
|
+
Account.nested_attributes.clear
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
let(:association) do
|
|
61
|
+
Account.reflect_on_association(:alerts)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "keeps autosave set to false" do
|
|
65
|
+
expect(association).to_not be_autosave
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe "#initialize" do
|
|
71
|
+
|
|
72
|
+
context "when the relation is an embeds one" do
|
|
73
|
+
|
|
74
|
+
before do
|
|
75
|
+
Person.send(:undef_method, :name_attributes=)
|
|
76
|
+
Person.accepts_nested_attributes_for :name
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
let(:person) do
|
|
80
|
+
Person.new(name_attributes: { first_name: "Johnny" })
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "sets the nested attributes" do
|
|
84
|
+
expect(person.name.first_name).to eq("Johnny")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context "when the relation is an embeds many" do
|
|
89
|
+
|
|
90
|
+
before do
|
|
91
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
92
|
+
Person.accepts_nested_attributes_for :addresses
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
let(:person) do
|
|
96
|
+
Person.new(addresses_attributes: { "1" => { street: "Alexanderstr" }})
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "sets the nested attributes" do
|
|
100
|
+
expect(person.addresses.first.street).to eq("Alexanderstr")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context "when there are 10 or more child records" do
|
|
104
|
+
|
|
105
|
+
let(:person) do
|
|
106
|
+
Person.new(addresses: addresses)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
let(:addresses) do
|
|
110
|
+
('0'..'10').inject({}) do |addresses,i|
|
|
111
|
+
addresses.merge(i => {number: i})
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "preserves the order of the children" do
|
|
116
|
+
expect(person.addresses.map(&:number)).to eq((0..10).to_a)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
context "when the association is referenced in and polymorphic" do
|
|
122
|
+
|
|
123
|
+
it "infers the class name of the polymorphic with the inverse type" do
|
|
124
|
+
expect {
|
|
125
|
+
Post.create!(
|
|
126
|
+
title: "Some title",
|
|
127
|
+
posteable_type: "Sandwich",
|
|
128
|
+
posteable_attributes: { name: 'Grilled Cheese' }
|
|
129
|
+
)
|
|
130
|
+
}.not_to raise_error
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "when the relation is an embedded in" do
|
|
135
|
+
|
|
136
|
+
before do
|
|
137
|
+
Video.accepts_nested_attributes_for :person
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
let(:video) do
|
|
141
|
+
Video.new(person_attributes: { title: "Sir" })
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "sets the nested attributes" do
|
|
145
|
+
expect(video.person.title).to eq("Sir")
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
context "when the relation is a references one" do
|
|
150
|
+
|
|
151
|
+
before do
|
|
152
|
+
Person.send(:undef_method, :game_attributes=)
|
|
153
|
+
Person.accepts_nested_attributes_for :game
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
let(:person) do
|
|
157
|
+
Person.new(game_attributes: { name: "Tron" })
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "sets the nested attributes" do
|
|
161
|
+
expect(person.game.name).to eq("Tron")
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
context "when the relation is a references many" do
|
|
166
|
+
|
|
167
|
+
before do
|
|
168
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
169
|
+
Person.accepts_nested_attributes_for :posts
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
let(:person) do
|
|
173
|
+
Person.new(posts_attributes: { "1" => { title: "First" }})
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "sets the nested attributes" do
|
|
177
|
+
expect(person.posts.first.title).to eq("First")
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
context "when the relation is a references and referenced in many" do
|
|
182
|
+
|
|
183
|
+
before do
|
|
184
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
185
|
+
Person.accepts_nested_attributes_for :preferences
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
let(:person) do
|
|
189
|
+
Person.new(preferences_attributes: { "1" => { name: "First" }})
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it "sets the nested attributes" do
|
|
193
|
+
expect(person.preferences.first.name).to eq("First")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
context "when adding existing document to a relation" do
|
|
197
|
+
let(:preference) { Preference.create!(name: 'sample preference') }
|
|
198
|
+
let(:person) do
|
|
199
|
+
Person.new(
|
|
200
|
+
preferences_attributes: { 0 => { id: preference.id, name: preference.name } }
|
|
201
|
+
)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "sets the nested attributes" do
|
|
205
|
+
expect(person.preferences.map(&:name)).to eq([preference.name])
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "updates attributes of existing document which is added to relation" do
|
|
209
|
+
preference_name = 'updated preference'
|
|
210
|
+
person = Person.new(
|
|
211
|
+
preferences_attributes: { 0 => { id: preference.id, name: preference_name } }
|
|
212
|
+
)
|
|
213
|
+
expect(person.preferences.map(&:name)).to eq([preference_name])
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context "when the relation is a referenced in" do
|
|
219
|
+
|
|
220
|
+
before do
|
|
221
|
+
Post.accepts_nested_attributes_for :person, autosave: false
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
after do
|
|
225
|
+
Post.send(:undef_method, :person_attributes=)
|
|
226
|
+
Post.nested_attributes.clear
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
let(:post) do
|
|
230
|
+
Post.new(person_attributes: { title: "Sir" })
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "sets the nested attributes" do
|
|
234
|
+
expect(post.person.title).to eq("Sir")
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
describe "*_attributes=" do
|
|
240
|
+
|
|
241
|
+
context "when the parent document is new" do
|
|
242
|
+
|
|
243
|
+
context "when the relation is an embeds one" do
|
|
244
|
+
|
|
245
|
+
context "when the parent document is persisted" do
|
|
246
|
+
|
|
247
|
+
let(:person) do
|
|
248
|
+
Person.create!
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
before do
|
|
252
|
+
Person.send(:undef_method, :name_attributes=)
|
|
253
|
+
Person.accepts_nested_attributes_for :name, allow_destroy: true
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
after do
|
|
257
|
+
Person.send(:undef_method, :name_attributes=)
|
|
258
|
+
Person.accepts_nested_attributes_for :name
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
context "when setting the child attributes" do
|
|
262
|
+
|
|
263
|
+
before do
|
|
264
|
+
person.name_attributes = { last_name: "Fischer" }
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it "sets the child document" do
|
|
268
|
+
expect(person.name.last_name).to eq("Fischer")
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it "does not persist the child document" do
|
|
272
|
+
expect(person.name).to_not be_persisted
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
context "when saving the parent" do
|
|
276
|
+
|
|
277
|
+
before do
|
|
278
|
+
person.save!
|
|
279
|
+
person.reload
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it "persists the child document" do
|
|
283
|
+
expect(person.name).to be_persisted
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
let(:person) do
|
|
290
|
+
Person.new
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
context "when a reject proc is specified" do
|
|
294
|
+
|
|
295
|
+
before do
|
|
296
|
+
Person.send(:undef_method, :name_attributes=)
|
|
297
|
+
Person.accepts_nested_attributes_for \
|
|
298
|
+
:name, reject_if: ->(attrs){ attrs[:first_name].blank? }
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
after do
|
|
302
|
+
Person.send(:undef_method, :name_attributes=)
|
|
303
|
+
Person.accepts_nested_attributes_for :name
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
context "when the attributes match" do
|
|
307
|
+
|
|
308
|
+
before do
|
|
309
|
+
person.name_attributes = { last_name: "Lang" }
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it "does not add the document" do
|
|
313
|
+
expect(person.name).to be_nil
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
context "when the attributes do not match" do
|
|
318
|
+
|
|
319
|
+
before do
|
|
320
|
+
person.name_attributes = { first_name: "Lang" }
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it "adds the document" do
|
|
324
|
+
expect(person.name.first_name).to eq("Lang")
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
context "when :reject_if => :all_blank is specified" do
|
|
330
|
+
|
|
331
|
+
context "when the relation is not autobuilding" do
|
|
332
|
+
|
|
333
|
+
before do
|
|
334
|
+
Person.send(:undef_method, :name_attributes=)
|
|
335
|
+
Person.accepts_nested_attributes_for \
|
|
336
|
+
:name, reject_if: :all_blank
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
after do
|
|
340
|
+
Person.send(:undef_method, :name_attributes=)
|
|
341
|
+
Person.accepts_nested_attributes_for :name
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
context "when all attributes are empty" do
|
|
345
|
+
|
|
346
|
+
before do
|
|
347
|
+
person.name_attributes = { last_name: "" }
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
it "does not add the document" do
|
|
351
|
+
expect(person.name).to be_nil
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
context "when an attribute is non-empty" do
|
|
356
|
+
|
|
357
|
+
before do
|
|
358
|
+
person.name_attributes = { first_name: "Lang" }
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
it "adds the document" do
|
|
362
|
+
expect(person.name.first_name).to eq("Lang")
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
context "when the relation is autobuilding" do
|
|
368
|
+
|
|
369
|
+
before do
|
|
370
|
+
Product.accepts_nested_attributes_for :seo, reject_if: :all_blank
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
after do
|
|
374
|
+
Product.send(:undef_method, :seo_attributes=)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
context "when all attributes are empty" do
|
|
378
|
+
|
|
379
|
+
let(:product) do
|
|
380
|
+
Product.create!(name: "testing")
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
it "does not add the document" do
|
|
384
|
+
expect(product.seo).to_not be_persisted
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
context "when no id has been passed" do
|
|
391
|
+
|
|
392
|
+
context "with no destroy attribute" do
|
|
393
|
+
|
|
394
|
+
before do
|
|
395
|
+
person.name_attributes = { first_name: "Leo" }
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
it "builds a new document" do
|
|
399
|
+
expect(person.name.first_name).to eq("Leo")
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
context "with a destroy attribute" do
|
|
404
|
+
|
|
405
|
+
context "when allow_destroy is true" do
|
|
406
|
+
|
|
407
|
+
before do
|
|
408
|
+
Person.send(:undef_method, :name_attributes=)
|
|
409
|
+
Person.accepts_nested_attributes_for :name, allow_destroy: true
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
after do
|
|
413
|
+
Person.send(:undef_method, :name_attributes=)
|
|
414
|
+
Person.accepts_nested_attributes_for :name
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
context "when destroy is a symbol" do
|
|
418
|
+
|
|
419
|
+
before do
|
|
420
|
+
person.name_attributes = { first_name: "Leo", _destroy: "1" }
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
it "does not build the document" do
|
|
424
|
+
expect(person.name).to be_nil
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
context "when destroy is a string" do
|
|
429
|
+
|
|
430
|
+
before do
|
|
431
|
+
person.name_attributes = { first_name: "Leo", "_destroy" => "1" }
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
it "does not build the document" do
|
|
435
|
+
expect(person.name).to be_nil
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
context "when allow_destroy is false" do
|
|
441
|
+
|
|
442
|
+
before do
|
|
443
|
+
Person.send(:undef_method, :name_attributes=)
|
|
444
|
+
Person.accepts_nested_attributes_for :name, allow_destroy: false
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
after do
|
|
448
|
+
Person.send(:undef_method, :name_attributes=)
|
|
449
|
+
Person.accepts_nested_attributes_for :name
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
before do
|
|
453
|
+
person.name_attributes = { first_name: "Leo", _destroy: "1" }
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
it "builds the document" do
|
|
457
|
+
expect(person.name.first_name).to eq("Leo")
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
context "with empty attributes" do
|
|
463
|
+
|
|
464
|
+
before do
|
|
465
|
+
person.name_attributes = {}
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
it "does not build the document" do
|
|
469
|
+
expect(person.name).to be_nil
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
context "when there is an existing document" do
|
|
474
|
+
|
|
475
|
+
context "with no destroy attribute" do
|
|
476
|
+
|
|
477
|
+
before do
|
|
478
|
+
person.name = Name.new(first_name: "Michael")
|
|
479
|
+
person.name_attributes = { first_name: "Jack" }
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
it "replaces the document" do
|
|
483
|
+
expect(person.name.first_name).to eq("Jack")
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
context "with a destroy attribute" do
|
|
488
|
+
|
|
489
|
+
context "when allow_destroy is true" do
|
|
490
|
+
|
|
491
|
+
before do
|
|
492
|
+
Person.send(:undef_method, :name_attributes=)
|
|
493
|
+
Person.accepts_nested_attributes_for :name, allow_destroy: true
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
after do
|
|
497
|
+
Person.send(:undef_method, :name_attributes=)
|
|
498
|
+
Person.accepts_nested_attributes_for :name
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
before do
|
|
502
|
+
person.name = Name.new(first_name: "Michael")
|
|
503
|
+
person.name_attributes = { first_name: "Jack", _destroy: "1" }
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
it "does not replace the document" do
|
|
507
|
+
expect(person.name.first_name).to eq("Michael")
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
context "when allow_destroy is false" do
|
|
512
|
+
|
|
513
|
+
before do
|
|
514
|
+
Person.send(:undef_method, :name_attributes=)
|
|
515
|
+
Person.accepts_nested_attributes_for :name, allow_destroy: false
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
after do
|
|
519
|
+
Person.send(:undef_method, :name_attributes=)
|
|
520
|
+
Person.accepts_nested_attributes_for :name
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
before do
|
|
524
|
+
person.name = Name.new(first_name: "Michael")
|
|
525
|
+
person.name_attributes = { first_name: "Jack", _destroy: "1" }
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
it "replaces the document" do
|
|
529
|
+
expect(person.name.first_name).to eq("Jack")
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
context "when an id is passed" do
|
|
537
|
+
|
|
538
|
+
context "when there is an existing record" do
|
|
539
|
+
|
|
540
|
+
let(:name) do
|
|
541
|
+
Name.new(first_name: "Joe")
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
before do
|
|
545
|
+
person.name = name
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
context "when the id matches" do
|
|
549
|
+
|
|
550
|
+
context "when passed keys as symbols" do
|
|
551
|
+
|
|
552
|
+
before do
|
|
553
|
+
person.name_attributes =
|
|
554
|
+
{ id: name.id.to_s, first_name: "Bob" }
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
it "updates the existing document" do
|
|
558
|
+
expect(person.name.first_name).to eq("Bob")
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
context "when passed keys as strings" do
|
|
563
|
+
|
|
564
|
+
before do
|
|
565
|
+
person.name_attributes =
|
|
566
|
+
{ "id" => name.id.to_s, "first_name" => "Bob" }
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
it "updates the existing document" do
|
|
570
|
+
expect(person.name.first_name).to eq("Bob")
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
context "when allow_destroy is true" do
|
|
575
|
+
|
|
576
|
+
before do
|
|
577
|
+
Person.send(:undef_method, :name_attributes=)
|
|
578
|
+
Person.accepts_nested_attributes_for :name, allow_destroy: true
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
after do
|
|
582
|
+
Person.send(:undef_method, :name_attributes=)
|
|
583
|
+
Person.accepts_nested_attributes_for :name
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
587
|
+
|
|
588
|
+
context "when passed #{truth} with destroy" do
|
|
589
|
+
|
|
590
|
+
context "when the document has no callbacks" do
|
|
591
|
+
|
|
592
|
+
before do
|
|
593
|
+
person.name_attributes =
|
|
594
|
+
{ id: name.id, _destroy: truth }
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
it "destroys the existing document" do
|
|
598
|
+
expect(person.name).to be_nil
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
context "when the document has destroy callbacks" do
|
|
603
|
+
|
|
604
|
+
before do
|
|
605
|
+
PetOwner.accepts_nested_attributes_for :pet, allow_destroy: true
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
after do
|
|
609
|
+
PetOwner.send(:undef_method, :pet_attributes=)
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
let(:owner) do
|
|
613
|
+
PetOwner.create!
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
let!(:pet) do
|
|
617
|
+
owner.create_pet
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
before do
|
|
621
|
+
owner.pet_attributes = { id: pet.id, _destroy: truth }
|
|
622
|
+
owner.save!
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
it "destroys the existing document" do
|
|
626
|
+
expect(owner.pet).to be_nil
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
it "runs the destroy callbacks" do
|
|
630
|
+
expect(pet.destroy_flag).to be true
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
[ nil, 0, "0", false, "false" ].each do |falsehood|
|
|
637
|
+
|
|
638
|
+
context "when passed #{falsehood} with destroy" do
|
|
639
|
+
|
|
640
|
+
before do
|
|
641
|
+
person.name_attributes =
|
|
642
|
+
{ id: name.id, _destroy: falsehood }
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
it "does not destroy the existing document" do
|
|
646
|
+
expect(person.name).to eq(name)
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
context "when allow destroy is false" do
|
|
653
|
+
|
|
654
|
+
before do
|
|
655
|
+
Person.send(:undef_method, :name_attributes=)
|
|
656
|
+
Person.accepts_nested_attributes_for :name, allow_destroy: false
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
after do
|
|
660
|
+
Person.send(:undef_method, :name_attributes=)
|
|
661
|
+
Person.accepts_nested_attributes_for :name
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
context "when a destroy attribute is passed" do
|
|
665
|
+
|
|
666
|
+
before do
|
|
667
|
+
person.name_attributes =
|
|
668
|
+
{ id: name.id, _destroy: true }
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
it "does not destroy the document" do
|
|
672
|
+
expect(person.name).to eq(name)
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
context "when update only is true" do
|
|
678
|
+
|
|
679
|
+
before do
|
|
680
|
+
Person.send(:undef_method, :name_attributes=)
|
|
681
|
+
Person.accepts_nested_attributes_for \
|
|
682
|
+
:name,
|
|
683
|
+
update_only: true,
|
|
684
|
+
allow_destroy: true
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
after do
|
|
688
|
+
Person.send(:undef_method, :name_attributes=)
|
|
689
|
+
Person.accepts_nested_attributes_for :name
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
context "when the id matches" do
|
|
693
|
+
|
|
694
|
+
before do
|
|
695
|
+
person.name_attributes =
|
|
696
|
+
{ id: name.id, first_name: "Ro" }
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
it "updates the existing document" do
|
|
700
|
+
expect(person.name.first_name).to eq("Ro")
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
context "when the id does not match" do
|
|
705
|
+
|
|
706
|
+
before do
|
|
707
|
+
person.name_attributes =
|
|
708
|
+
{ id: BSON::ObjectId.new.to_s, first_name: "Durran" }
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
it "updates the existing document" do
|
|
712
|
+
expect(person.name.first_name).to eq("Durran")
|
|
713
|
+
end
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
context "when passed a destroy truth" do
|
|
717
|
+
|
|
718
|
+
before do
|
|
719
|
+
person.name_attributes =
|
|
720
|
+
{ id: name.id, _destroy: true }
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
it "destroys the existing document" do
|
|
724
|
+
expect(person.name).to be_nil
|
|
725
|
+
end
|
|
726
|
+
end
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
context "when ids are ObjectId strings" do
|
|
730
|
+
|
|
731
|
+
let(:quiz) do
|
|
732
|
+
person.quiz = Quiz.new(topic: "Math")
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
before do
|
|
736
|
+
person.quiz_attributes = {
|
|
737
|
+
"id" => quiz.id.to_s, topic: "English"
|
|
738
|
+
}
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
it "updates the existing document" do
|
|
742
|
+
expect(person.quiz.topic).to eq("English")
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
context "when the nested document is invalid" do
|
|
750
|
+
|
|
751
|
+
before do
|
|
752
|
+
Person.validates_associated(:pet)
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
after do
|
|
756
|
+
Person.reset_callbacks(:validate)
|
|
757
|
+
end
|
|
758
|
+
|
|
759
|
+
before do
|
|
760
|
+
person.pet_attributes = { name: "$$$" }
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
it "propagates invalidity to parent" do
|
|
764
|
+
expect(person.pet).to_not be_valid
|
|
765
|
+
expect(person).to_not be_valid
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
context "when a type is passed" do
|
|
770
|
+
|
|
771
|
+
let(:canvas) do
|
|
772
|
+
Canvas.new
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
before do
|
|
776
|
+
Canvas.send(:undef_method, :writer_attributes=)
|
|
777
|
+
Canvas.accepts_nested_attributes_for :writer
|
|
778
|
+
canvas.writer_attributes = { _type: "HtmlWriter" }
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
it "instantiates an object of the given type" do
|
|
782
|
+
expect(canvas.writer.class).to eq(HtmlWriter)
|
|
783
|
+
end
|
|
784
|
+
end
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
context "when the relation is embedded in" do
|
|
788
|
+
|
|
789
|
+
context "when the child is new" do
|
|
790
|
+
|
|
791
|
+
let(:animal) do
|
|
792
|
+
Animal.new
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
context "when no id has been passed" do
|
|
796
|
+
|
|
797
|
+
context "when no destroy attribute passed" do
|
|
798
|
+
|
|
799
|
+
before do
|
|
800
|
+
animal.person_attributes = { title: "Sir" }
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
it "builds a new document" do
|
|
804
|
+
expect(animal.person.title).to eq("Sir")
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
context "when a destroy attribute is passed" do
|
|
810
|
+
|
|
811
|
+
context "when allow_destroy is true" do
|
|
812
|
+
|
|
813
|
+
before do
|
|
814
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
815
|
+
Animal.accepts_nested_attributes_for :person, allow_destroy: true
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
after do
|
|
819
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
820
|
+
Animal.accepts_nested_attributes_for :person
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
before do
|
|
824
|
+
animal.person_attributes = { title: "Sir", _destroy: 1 }
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
it "does not build a new document" do
|
|
828
|
+
expect(animal.person).to be_nil
|
|
829
|
+
end
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
context "when allow_destroy is false" do
|
|
833
|
+
|
|
834
|
+
before do
|
|
835
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
836
|
+
Animal.accepts_nested_attributes_for :person, allow_destroy: false
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
after do
|
|
840
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
841
|
+
Animal.accepts_nested_attributes_for :person
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
before do
|
|
845
|
+
animal.person_attributes = { title: "Sir", _destroy: 1 }
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
it "builds a new document" do
|
|
849
|
+
expect(animal.person.title).to eq("Sir")
|
|
850
|
+
end
|
|
851
|
+
end
|
|
852
|
+
end
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
context "when an id has been passed" do
|
|
856
|
+
|
|
857
|
+
let(:person) do
|
|
858
|
+
Person.new
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
context "when no destroy attribute passed" do
|
|
862
|
+
|
|
863
|
+
context "when the id matches" do
|
|
864
|
+
|
|
865
|
+
before do
|
|
866
|
+
animal.person_attributes = { id: person.id, title: "Sir" }
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
it "updates the existing document" do
|
|
870
|
+
expect(animal.person.title).to eq("Sir")
|
|
871
|
+
end
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
context "when there is an existing document" do
|
|
876
|
+
|
|
877
|
+
before do
|
|
878
|
+
animal.person = person
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
context "when allow destroy is true" do
|
|
882
|
+
|
|
883
|
+
before do
|
|
884
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
885
|
+
Animal.accepts_nested_attributes_for :person, allow_destroy: true
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
after do
|
|
889
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
890
|
+
Animal.accepts_nested_attributes_for :person
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
894
|
+
|
|
895
|
+
context "when passed #{truth} with destroy" do
|
|
896
|
+
|
|
897
|
+
before do
|
|
898
|
+
animal.person_attributes =
|
|
899
|
+
{ id: person.id, _destroy: truth }
|
|
900
|
+
end
|
|
901
|
+
|
|
902
|
+
it "destroys the existing document" do
|
|
903
|
+
expect(animal.person).to be_nil
|
|
904
|
+
end
|
|
905
|
+
end
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
[ nil, 0, "0", false, "false" ].each do |falsehood|
|
|
909
|
+
|
|
910
|
+
context "when passed #{falsehood} with destroy" do
|
|
911
|
+
|
|
912
|
+
before do
|
|
913
|
+
animal.person_attributes =
|
|
914
|
+
{ id: person.id, _destroy: falsehood }
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
it "does not destroy the existing document" do
|
|
918
|
+
expect(animal.person).to eq(person)
|
|
919
|
+
end
|
|
920
|
+
end
|
|
921
|
+
end
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
context "when allow destroy is false" do
|
|
925
|
+
|
|
926
|
+
before do
|
|
927
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
928
|
+
Animal.accepts_nested_attributes_for :person, allow_destroy: false
|
|
929
|
+
end
|
|
930
|
+
|
|
931
|
+
after do
|
|
932
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
933
|
+
Animal.accepts_nested_attributes_for :person
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
context "when a destroy attribute is passed" do
|
|
937
|
+
|
|
938
|
+
before do
|
|
939
|
+
animal.person_attributes =
|
|
940
|
+
{ id: person.id, _destroy: true }
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
it "does not delete the document" do
|
|
944
|
+
expect(animal.person).to eq(person)
|
|
945
|
+
end
|
|
946
|
+
end
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
context "when update only is true" do
|
|
950
|
+
|
|
951
|
+
before do
|
|
952
|
+
Animal.send(:undef_method, :person_attributes=)
|
|
953
|
+
Animal.accepts_nested_attributes_for \
|
|
954
|
+
:person,
|
|
955
|
+
update_only: true,
|
|
956
|
+
allow_destroy: true
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
context "when the id matches" do
|
|
960
|
+
|
|
961
|
+
before do
|
|
962
|
+
animal.person_attributes =
|
|
963
|
+
{ id: person.id, title: "Madam" }
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
it "updates the existing document" do
|
|
967
|
+
expect(animal.person.title).to eq("Madam")
|
|
968
|
+
end
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
context "when the id does not match" do
|
|
972
|
+
|
|
973
|
+
before do
|
|
974
|
+
animal.person_attributes =
|
|
975
|
+
{ id: BSON::ObjectId.new.to_s, title: "Madam" }
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
it "updates the existing document" do
|
|
979
|
+
expect(animal.person.title).to eq("Madam")
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
context "when passed a destroy truth" do
|
|
984
|
+
|
|
985
|
+
before do
|
|
986
|
+
animal.person_attributes =
|
|
987
|
+
{ id: person.id, title: "Madam", _destroy: "true" }
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
it "deletes the existing document" do
|
|
991
|
+
expect(animal.person).to be_nil
|
|
992
|
+
end
|
|
993
|
+
end
|
|
994
|
+
end
|
|
995
|
+
end
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
context "when the nested document is invalid" do
|
|
999
|
+
|
|
1000
|
+
before do
|
|
1001
|
+
Person.validates_format_of :ssn, without: /\$\$\$/
|
|
1002
|
+
end
|
|
1003
|
+
|
|
1004
|
+
after do
|
|
1005
|
+
Person.reset_callbacks(:validate)
|
|
1006
|
+
end
|
|
1007
|
+
|
|
1008
|
+
before do
|
|
1009
|
+
animal.person_attributes = { ssn: '$$$' }
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
it "does not propagate invalidity to parent" do
|
|
1013
|
+
expect(animal.person).to_not be_valid
|
|
1014
|
+
expect(animal).to be_valid
|
|
1015
|
+
end
|
|
1016
|
+
end
|
|
1017
|
+
end
|
|
1018
|
+
|
|
1019
|
+
context "when a type is passed" do
|
|
1020
|
+
|
|
1021
|
+
let(:tool) do
|
|
1022
|
+
Tool.new
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
before do
|
|
1026
|
+
tool.palette_attributes ={ _type: "BigPalette" }
|
|
1027
|
+
end
|
|
1028
|
+
|
|
1029
|
+
it "instantiates an object of the given type" do
|
|
1030
|
+
expect(tool.palette.class).to eq(BigPalette)
|
|
1031
|
+
end
|
|
1032
|
+
end
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
context "when the relation is an embeds many" do
|
|
1036
|
+
|
|
1037
|
+
context "when the parent document is persisted" do
|
|
1038
|
+
|
|
1039
|
+
let(:person) do
|
|
1040
|
+
Person.create!
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
before do
|
|
1044
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1045
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
after do
|
|
1049
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1050
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
context "when setting the child attributes" do
|
|
1054
|
+
|
|
1055
|
+
let(:attributes) do
|
|
1056
|
+
{ "foo" => { "street" => "Maybachufer" } }
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1059
|
+
before do
|
|
1060
|
+
person.addresses_attributes = attributes
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
it "sets the child documents" do
|
|
1064
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
it "does not persist the child documents" do
|
|
1068
|
+
expect(person.addresses.first).to_not be_persisted
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
context "when saving the parent" do
|
|
1072
|
+
|
|
1073
|
+
before do
|
|
1074
|
+
person.save!
|
|
1075
|
+
person.reload
|
|
1076
|
+
end
|
|
1077
|
+
|
|
1078
|
+
it "saves the child documents" do
|
|
1079
|
+
expect(person.addresses.first).to be_persisted
|
|
1080
|
+
end
|
|
1081
|
+
end
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
let(:person) do
|
|
1086
|
+
Person.new
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
let(:address_one) do
|
|
1090
|
+
Address.new(street: "Unter den Linden")
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
let(:address_two) do
|
|
1094
|
+
Address.new(street: "Kurfeurstendamm")
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1097
|
+
context "when a limit is specified" do
|
|
1098
|
+
|
|
1099
|
+
before do
|
|
1100
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1101
|
+
Person.accepts_nested_attributes_for :addresses, limit: 2
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
after do
|
|
1105
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1106
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1107
|
+
end
|
|
1108
|
+
|
|
1109
|
+
context "when more are provided than the limit" do
|
|
1110
|
+
|
|
1111
|
+
let(:attributes) do
|
|
1112
|
+
{
|
|
1113
|
+
"foo" => { "street" => "Maybachufer" },
|
|
1114
|
+
"bar" => { "street" => "Alexander Platz" },
|
|
1115
|
+
"baz" => { "street" => "Unter den Linden" }
|
|
1116
|
+
}
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
it "raises an error" do
|
|
1120
|
+
expect {
|
|
1121
|
+
person.addresses_attributes = attributes
|
|
1122
|
+
}.to raise_error(Mongoid::Errors::TooManyNestedAttributeRecords)
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
context "when less are provided than the limit" do
|
|
1127
|
+
|
|
1128
|
+
let(:attributes) do
|
|
1129
|
+
{
|
|
1130
|
+
"foo" => { "street" => "Maybachufer" },
|
|
1131
|
+
"bar" => { "street" => "Alexander Platz" }
|
|
1132
|
+
}
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
before do
|
|
1136
|
+
person.addresses_attributes = attributes
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
it "sets the documents on the relation" do
|
|
1140
|
+
expect(person.addresses.size).to eq(2)
|
|
1141
|
+
end
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
context "when an array of attributes are passed" do
|
|
1145
|
+
|
|
1146
|
+
let(:attributes) do
|
|
1147
|
+
[
|
|
1148
|
+
{ "street" => "Maybachufer" },
|
|
1149
|
+
{ "street" => "Alexander Platz" }
|
|
1150
|
+
]
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
before do
|
|
1154
|
+
person.addresses_attributes = attributes
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
it "sets the documents on the relation" do
|
|
1158
|
+
expect(person.addresses.size).to eq(2)
|
|
1159
|
+
end
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
context "when cascading callbacks" do
|
|
1163
|
+
|
|
1164
|
+
before do
|
|
1165
|
+
Band.accepts_nested_attributes_for :records
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
after do
|
|
1169
|
+
Band.send(:undef_method, :records_attributes=)
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
let(:band) do
|
|
1173
|
+
Band.new
|
|
1174
|
+
end
|
|
1175
|
+
|
|
1176
|
+
let(:attributes) do
|
|
1177
|
+
[
|
|
1178
|
+
{ "name" => "101" },
|
|
1179
|
+
{ "name" => "Ultra" }
|
|
1180
|
+
]
|
|
1181
|
+
end
|
|
1182
|
+
|
|
1183
|
+
before do
|
|
1184
|
+
band.records_attributes = attributes
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
context "when the parent is saved" do
|
|
1188
|
+
|
|
1189
|
+
before do
|
|
1190
|
+
band.save!
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
it "runs the first child create callbacks" do
|
|
1194
|
+
expect(band.records.first.before_create_called).to be true
|
|
1195
|
+
end
|
|
1196
|
+
|
|
1197
|
+
it "runs the last child create callbacks" do
|
|
1198
|
+
expect(band.records.last.before_create_called).to be true
|
|
1199
|
+
end
|
|
1200
|
+
end
|
|
1201
|
+
end
|
|
1202
|
+
end
|
|
1203
|
+
|
|
1204
|
+
context "when ids are passed" do
|
|
1205
|
+
|
|
1206
|
+
before do
|
|
1207
|
+
person.addresses << [ address_one, address_two ]
|
|
1208
|
+
end
|
|
1209
|
+
|
|
1210
|
+
context "when no destroy attributes are passed" do
|
|
1211
|
+
|
|
1212
|
+
context "when the ids match" do
|
|
1213
|
+
|
|
1214
|
+
before do
|
|
1215
|
+
person.addresses_attributes =
|
|
1216
|
+
{
|
|
1217
|
+
"foo" => { "id" => address_one.id, "street" => "Maybachufer" },
|
|
1218
|
+
"bar" => { "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1219
|
+
}
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
it "updates the first existing document" do
|
|
1223
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1226
|
+
it "updates the second existing document" do
|
|
1227
|
+
expect(person.addresses.second.street).to eq("Alexander Platz")
|
|
1228
|
+
end
|
|
1229
|
+
|
|
1230
|
+
it "does not add new documents" do
|
|
1231
|
+
expect(person.addresses.size).to eq(2)
|
|
1232
|
+
end
|
|
1233
|
+
end
|
|
1234
|
+
|
|
1235
|
+
context "when the ids match in an array of attributes" do
|
|
1236
|
+
|
|
1237
|
+
context "when passing in id" do
|
|
1238
|
+
|
|
1239
|
+
before do
|
|
1240
|
+
person.addresses_attributes =
|
|
1241
|
+
[
|
|
1242
|
+
{ "id" => address_one.id, "street" => "Maybachufer" },
|
|
1243
|
+
{ "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1244
|
+
]
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
it "updates the first existing document" do
|
|
1248
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
it "updates the second existing document" do
|
|
1252
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1255
|
+
it "does not add new documents" do
|
|
1256
|
+
expect(person.addresses.size).to eq(2)
|
|
1257
|
+
end
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
context "when passing in _id" do
|
|
1261
|
+
|
|
1262
|
+
before do
|
|
1263
|
+
person.addresses_attributes =
|
|
1264
|
+
[
|
|
1265
|
+
{ "_id" => address_one.id, "street" => "Maybachufer" },
|
|
1266
|
+
{ "_id" => address_two.id, "street" => "Alexander Platz" }
|
|
1267
|
+
]
|
|
1268
|
+
end
|
|
1269
|
+
|
|
1270
|
+
it "updates the first existing document" do
|
|
1271
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
|
|
1272
|
+
end
|
|
1273
|
+
|
|
1274
|
+
it "updates the second existing document" do
|
|
1275
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
|
|
1276
|
+
end
|
|
1277
|
+
|
|
1278
|
+
it "does not add new documents" do
|
|
1279
|
+
expect(person.addresses.size).to eq(2)
|
|
1280
|
+
end
|
|
1281
|
+
end
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
context "when the ids match in an array of attributes and start with '_'" do
|
|
1285
|
+
|
|
1286
|
+
before do
|
|
1287
|
+
person.addresses_attributes =
|
|
1288
|
+
[
|
|
1289
|
+
{ "_id" => address_one.id, "street" => "Maybachufer" },
|
|
1290
|
+
{ "_id" => address_two.id, "street" => "Alexander Platz" }
|
|
1291
|
+
]
|
|
1292
|
+
end
|
|
1293
|
+
|
|
1294
|
+
it "updates the first existing document" do
|
|
1295
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
|
|
1296
|
+
end
|
|
1297
|
+
|
|
1298
|
+
it "updates the second existing document" do
|
|
1299
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
it "does not add new documents" do
|
|
1303
|
+
expect(person.addresses.size).to eq(2)
|
|
1304
|
+
end
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
context "when the ids are _id symbols" do
|
|
1308
|
+
|
|
1309
|
+
before do
|
|
1310
|
+
person.addresses_attributes =
|
|
1311
|
+
[
|
|
1312
|
+
{ _id: address_one.id, "street" => "Maybachufer" },
|
|
1313
|
+
{ _id: address_two.id, "street" => "Alexander Platz" }
|
|
1314
|
+
]
|
|
1315
|
+
end
|
|
1316
|
+
|
|
1317
|
+
it "updates the first existing document" do
|
|
1318
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
|
|
1319
|
+
end
|
|
1320
|
+
|
|
1321
|
+
it "updates the second existing document" do
|
|
1322
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
|
|
1323
|
+
end
|
|
1324
|
+
|
|
1325
|
+
it "does not add new documents" do
|
|
1326
|
+
expect(person.addresses.size).to eq(2)
|
|
1327
|
+
end
|
|
1328
|
+
end
|
|
1329
|
+
|
|
1330
|
+
context "when the ids are id symbols" do
|
|
1331
|
+
|
|
1332
|
+
before do
|
|
1333
|
+
person.addresses_attributes =
|
|
1334
|
+
[
|
|
1335
|
+
{ id: address_one.id, "street" => "Maybachufer" },
|
|
1336
|
+
{ id: address_two.id, "street" => "Alexander Platz" }
|
|
1337
|
+
]
|
|
1338
|
+
end
|
|
1339
|
+
|
|
1340
|
+
it "updates the first existing document" do
|
|
1341
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Maybachufer')
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1344
|
+
it "updates the second existing document" do
|
|
1345
|
+
expect(person.addresses.collect { |a| a['street'] }).to include('Alexander Platz')
|
|
1346
|
+
end
|
|
1347
|
+
|
|
1348
|
+
it "does not add new documents" do
|
|
1349
|
+
expect(person.addresses.size).to eq(2)
|
|
1350
|
+
end
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1353
|
+
context "when the ids do not match" do
|
|
1354
|
+
|
|
1355
|
+
it "raises an error" do
|
|
1356
|
+
expect {
|
|
1357
|
+
person.addresses_attributes =
|
|
1358
|
+
{ "foo" => { "id" => "test", "street" => "Test" } }
|
|
1359
|
+
}.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Address with id\(s\)/)
|
|
1360
|
+
end
|
|
1361
|
+
end
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
context "when destroy attributes are passed" do
|
|
1365
|
+
|
|
1366
|
+
context "when the ids match" do
|
|
1367
|
+
|
|
1368
|
+
context "when allow_destroy is true" do
|
|
1369
|
+
|
|
1370
|
+
context "when the parent validation failed" do
|
|
1371
|
+
|
|
1372
|
+
class BandWithAllowDestroyedRecords < Band
|
|
1373
|
+
validates_presence_of :name
|
|
1374
|
+
accepts_nested_attributes_for :records, :allow_destroy => true
|
|
1375
|
+
end
|
|
1376
|
+
|
|
1377
|
+
let!(:band) do
|
|
1378
|
+
BandWithAllowDestroyedRecords.create(name: "Depeche Mode")
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1381
|
+
let!(:record) do
|
|
1382
|
+
band.records.create!
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
let(:attributes) do
|
|
1386
|
+
{
|
|
1387
|
+
name: nil,
|
|
1388
|
+
records_attributes: { "foo" => { "id" => record.id, "_destroy" => true }}
|
|
1389
|
+
}
|
|
1390
|
+
end
|
|
1391
|
+
|
|
1392
|
+
before do
|
|
1393
|
+
band.update_attributes(attributes)
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
it "does not remove the child document" do
|
|
1397
|
+
expect(band.records).to_not be_empty
|
|
1398
|
+
end
|
|
1399
|
+
|
|
1400
|
+
it "keeps the child flagged for destruction" do
|
|
1401
|
+
expect(record).to be_flagged_for_destroy
|
|
1402
|
+
end
|
|
1403
|
+
|
|
1404
|
+
it "does not persist any change" do
|
|
1405
|
+
expect(band.reload.records).to eq([ record ])
|
|
1406
|
+
end
|
|
1407
|
+
end
|
|
1408
|
+
|
|
1409
|
+
context "when the child accesses the parent after destroy" do
|
|
1410
|
+
|
|
1411
|
+
before do
|
|
1412
|
+
Band.accepts_nested_attributes_for :records, :allow_destroy => true
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1415
|
+
after do
|
|
1416
|
+
Band.send(:undef_method, :records_attributes=)
|
|
1417
|
+
end
|
|
1418
|
+
|
|
1419
|
+
let!(:band) do
|
|
1420
|
+
Band.create!
|
|
1421
|
+
end
|
|
1422
|
+
|
|
1423
|
+
let!(:record) do
|
|
1424
|
+
band.records.create!
|
|
1425
|
+
end
|
|
1426
|
+
|
|
1427
|
+
before do
|
|
1428
|
+
band.records_attributes =
|
|
1429
|
+
{ "foo" => { "id" => record.id, "_destroy" => true }}
|
|
1430
|
+
band.save!
|
|
1431
|
+
end
|
|
1432
|
+
|
|
1433
|
+
it "deletes the child document" do
|
|
1434
|
+
expect(band.records).to be_empty
|
|
1435
|
+
end
|
|
1436
|
+
|
|
1437
|
+
it "persists the changes" do
|
|
1438
|
+
expect(band.reload.records).to be_empty
|
|
1439
|
+
end
|
|
1440
|
+
end
|
|
1441
|
+
|
|
1442
|
+
context "when the child has defaults" do
|
|
1443
|
+
|
|
1444
|
+
before do
|
|
1445
|
+
Person.accepts_nested_attributes_for :appointments, allow_destroy: true
|
|
1446
|
+
end
|
|
1447
|
+
|
|
1448
|
+
after do
|
|
1449
|
+
Person.send(:undef_method, :appointments_attributes=)
|
|
1450
|
+
end
|
|
1451
|
+
|
|
1452
|
+
context "when the parent is persisted" do
|
|
1453
|
+
|
|
1454
|
+
let!(:persisted) do
|
|
1455
|
+
Person.create!(age: 42)
|
|
1456
|
+
end
|
|
1457
|
+
|
|
1458
|
+
context "when the child halts the callback chain in a before callback" do
|
|
1459
|
+
|
|
1460
|
+
context "when the child is not paranoid" do
|
|
1461
|
+
|
|
1462
|
+
let(:actor) do
|
|
1463
|
+
Actor.create!
|
|
1464
|
+
end
|
|
1465
|
+
|
|
1466
|
+
let!(:thing) do
|
|
1467
|
+
actor.things.create!
|
|
1468
|
+
end
|
|
1469
|
+
|
|
1470
|
+
before do
|
|
1471
|
+
actor.things_attributes =
|
|
1472
|
+
{ "foo" => { "id" => thing.id, "_destroy" => true }}
|
|
1473
|
+
actor.save
|
|
1474
|
+
end
|
|
1475
|
+
|
|
1476
|
+
it "does not destroy the child" do
|
|
1477
|
+
expect(actor.reload.things).to_not be_empty
|
|
1478
|
+
end
|
|
1479
|
+
end
|
|
1480
|
+
end
|
|
1481
|
+
|
|
1482
|
+
context "when only 1 child has the default persisted" do
|
|
1483
|
+
|
|
1484
|
+
let!(:app_one) do
|
|
1485
|
+
persisted.appointments.create!
|
|
1486
|
+
end
|
|
1487
|
+
|
|
1488
|
+
let!(:app_two) do
|
|
1489
|
+
persisted.appointments.create!.tap do |app|
|
|
1490
|
+
app.unset(:timed)
|
|
1491
|
+
end
|
|
1492
|
+
end
|
|
1493
|
+
|
|
1494
|
+
context "when destroying both children" do
|
|
1495
|
+
|
|
1496
|
+
let(:from_db) do
|
|
1497
|
+
Person.find(persisted.id)
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
before do
|
|
1501
|
+
from_db.appointments_attributes =
|
|
1502
|
+
{
|
|
1503
|
+
"bar" => { "id" => app_one.id, "_destroy" => true },
|
|
1504
|
+
"foo" => { "id" => app_two.id, "_destroy" => true }
|
|
1505
|
+
}
|
|
1506
|
+
from_db.save!
|
|
1507
|
+
end
|
|
1508
|
+
|
|
1509
|
+
it "destroys both children" do
|
|
1510
|
+
expect(from_db.appointments).to be_empty
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
it "persists the deletes" do
|
|
1514
|
+
expect(from_db.reload.appointments).to be_empty
|
|
1515
|
+
end
|
|
1516
|
+
end
|
|
1517
|
+
end
|
|
1518
|
+
end
|
|
1519
|
+
end
|
|
1520
|
+
|
|
1521
|
+
context "when the child is not paranoid" do
|
|
1522
|
+
|
|
1523
|
+
before do
|
|
1524
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1525
|
+
Person.accepts_nested_attributes_for :addresses, allow_destroy: true
|
|
1526
|
+
end
|
|
1527
|
+
|
|
1528
|
+
after do
|
|
1529
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1530
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1531
|
+
end
|
|
1532
|
+
|
|
1533
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
1534
|
+
|
|
1535
|
+
context "when passed a #{truth} with destroy" do
|
|
1536
|
+
|
|
1537
|
+
context "when the parent is new" do
|
|
1538
|
+
|
|
1539
|
+
context "when provided a hash of attributes" do
|
|
1540
|
+
|
|
1541
|
+
before do
|
|
1542
|
+
person.addresses_attributes =
|
|
1543
|
+
{
|
|
1544
|
+
"bar" => { "id" => address_one.id.to_s, "_destroy" => truth },
|
|
1545
|
+
"foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1546
|
+
}
|
|
1547
|
+
end
|
|
1548
|
+
|
|
1549
|
+
it "deletes the marked document" do
|
|
1550
|
+
expect(person.addresses.size).to eq(1)
|
|
1551
|
+
end
|
|
1552
|
+
|
|
1553
|
+
it "does not delete the unmarked document" do
|
|
1554
|
+
expect(person.addresses.first.street).to eq("Alexander Platz")
|
|
1555
|
+
end
|
|
1556
|
+
end
|
|
1557
|
+
|
|
1558
|
+
context "when provided an array of attributes" do
|
|
1559
|
+
|
|
1560
|
+
before do
|
|
1561
|
+
person.addresses_attributes =
|
|
1562
|
+
[
|
|
1563
|
+
{ "id" => address_one.id.to_s, "_destroy" => truth },
|
|
1564
|
+
{ "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1565
|
+
]
|
|
1566
|
+
end
|
|
1567
|
+
|
|
1568
|
+
it "deletes the marked document" do
|
|
1569
|
+
expect(person.addresses.size).to eq(1)
|
|
1570
|
+
end
|
|
1571
|
+
|
|
1572
|
+
it "does not delete the unmarked document" do
|
|
1573
|
+
expect(person.addresses.first.street).to eq("Alexander Platz")
|
|
1574
|
+
end
|
|
1575
|
+
end
|
|
1576
|
+
end
|
|
1577
|
+
|
|
1578
|
+
context "when the parent is persisted" do
|
|
1579
|
+
|
|
1580
|
+
let!(:persisted) do
|
|
1581
|
+
Person.create! do |p|
|
|
1582
|
+
p.addresses << [ address_one, address_two ]
|
|
1583
|
+
end
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
context "when setting, pulling, and pushing in one op" do
|
|
1587
|
+
|
|
1588
|
+
before do
|
|
1589
|
+
persisted.addresses_attributes =
|
|
1590
|
+
{
|
|
1591
|
+
"bar" => { "id" => address_one.id, "_destroy" => truth },
|
|
1592
|
+
"foo" => { "id" => address_two.id, "street" => "Alexander Platz" },
|
|
1593
|
+
"baz" => { "street" => "Potsdammer Platz" }
|
|
1594
|
+
}
|
|
1595
|
+
end
|
|
1596
|
+
|
|
1597
|
+
it "does not remove the first document from the relation" do
|
|
1598
|
+
expect(persisted.addresses.size).to eq(3)
|
|
1599
|
+
end
|
|
1600
|
+
|
|
1601
|
+
it "flags the destroyed document for removal" do
|
|
1602
|
+
expect(address_one).to be_marked_for_destruction
|
|
1603
|
+
end
|
|
1604
|
+
|
|
1605
|
+
it "does not delete the unmarked document" do
|
|
1606
|
+
expect(persisted.addresses.second.street).to eq(
|
|
1607
|
+
"Alexander Platz"
|
|
1608
|
+
)
|
|
1609
|
+
end
|
|
1610
|
+
|
|
1611
|
+
it "adds the new document to the relation" do
|
|
1612
|
+
expect(persisted.addresses.last.street).to eq(
|
|
1613
|
+
"Potsdammer Platz"
|
|
1614
|
+
)
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
it "has the proper persisted count" do
|
|
1618
|
+
expect(persisted.addresses.count).to eq(2)
|
|
1619
|
+
end
|
|
1620
|
+
|
|
1621
|
+
it "does not delete the removed document" do
|
|
1622
|
+
expect(address_one).to_not be_destroyed
|
|
1623
|
+
end
|
|
1624
|
+
|
|
1625
|
+
context "when saving the parent" do
|
|
1626
|
+
|
|
1627
|
+
before do
|
|
1628
|
+
persisted.save!
|
|
1629
|
+
end
|
|
1630
|
+
|
|
1631
|
+
it "deletes the marked document from the relation" do
|
|
1632
|
+
expect(persisted.reload.addresses.count).to eq(2)
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1635
|
+
it "does not delete the unmarked document" do
|
|
1636
|
+
expect(persisted.reload.addresses.first.street).to eq(
|
|
1637
|
+
"Alexander Platz"
|
|
1638
|
+
)
|
|
1639
|
+
end
|
|
1640
|
+
|
|
1641
|
+
it "persists the new document to the relation" do
|
|
1642
|
+
expect(persisted.reload.addresses.last.street).to eq(
|
|
1643
|
+
"Potsdammer Platz"
|
|
1644
|
+
)
|
|
1645
|
+
end
|
|
1646
|
+
end
|
|
1647
|
+
end
|
|
1648
|
+
|
|
1649
|
+
context "when pulling and pushing in one op" do
|
|
1650
|
+
|
|
1651
|
+
before do
|
|
1652
|
+
persisted.addresses_attributes =
|
|
1653
|
+
{
|
|
1654
|
+
"bar" => { "id" => address_one.id, "_destroy" => truth },
|
|
1655
|
+
"baz" => { "street" => "Potsdammer Platz" }
|
|
1656
|
+
}
|
|
1657
|
+
end
|
|
1658
|
+
|
|
1659
|
+
it "does not remove the first document from the relation" do
|
|
1660
|
+
expect(persisted.addresses.size).to eq(3)
|
|
1661
|
+
end
|
|
1662
|
+
|
|
1663
|
+
it "marks the first document for destruction" do
|
|
1664
|
+
expect(address_one).to be_marked_for_destruction
|
|
1665
|
+
end
|
|
1666
|
+
|
|
1667
|
+
it "adds the new document to the relation" do
|
|
1668
|
+
expect(persisted.addresses.last.street).to eq(
|
|
1669
|
+
"Potsdammer Platz"
|
|
1670
|
+
)
|
|
1671
|
+
end
|
|
1672
|
+
|
|
1673
|
+
it "has the proper persisted count" do
|
|
1674
|
+
expect(persisted.addresses.count).to eq(2)
|
|
1675
|
+
end
|
|
1676
|
+
|
|
1677
|
+
it "does not delete the removed document" do
|
|
1678
|
+
expect(address_one).to_not be_destroyed
|
|
1679
|
+
end
|
|
1680
|
+
|
|
1681
|
+
context "when saving the parent" do
|
|
1682
|
+
|
|
1683
|
+
before do
|
|
1684
|
+
persisted.save!
|
|
1685
|
+
end
|
|
1686
|
+
|
|
1687
|
+
it "deletes the marked document from the relation" do
|
|
1688
|
+
expect(persisted.reload.addresses.count).to eq(2)
|
|
1689
|
+
end
|
|
1690
|
+
|
|
1691
|
+
it "persists the new document to the relation" do
|
|
1692
|
+
expect(persisted.reload.addresses.last.street).to eq(
|
|
1693
|
+
"Potsdammer Platz"
|
|
1694
|
+
)
|
|
1695
|
+
end
|
|
1696
|
+
end
|
|
1697
|
+
end
|
|
1698
|
+
end
|
|
1699
|
+
end
|
|
1700
|
+
end
|
|
1701
|
+
|
|
1702
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
1703
|
+
|
|
1704
|
+
context "when passed a #{falsehood} with destroy" do
|
|
1705
|
+
|
|
1706
|
+
before do
|
|
1707
|
+
person.addresses_attributes =
|
|
1708
|
+
{
|
|
1709
|
+
"bar" => { "id" => address_one.id, "_destroy" => falsehood },
|
|
1710
|
+
"foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1711
|
+
}
|
|
1712
|
+
end
|
|
1713
|
+
|
|
1714
|
+
it "does not delete the marked document" do
|
|
1715
|
+
expect(person.addresses.size).to eq(2)
|
|
1716
|
+
end
|
|
1717
|
+
|
|
1718
|
+
it "does not delete the unmarked document" do
|
|
1719
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
1720
|
+
end
|
|
1721
|
+
end
|
|
1722
|
+
end
|
|
1723
|
+
end
|
|
1724
|
+
end
|
|
1725
|
+
|
|
1726
|
+
context "when allow_destroy is false" do
|
|
1727
|
+
|
|
1728
|
+
before do
|
|
1729
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1730
|
+
Person.accepts_nested_attributes_for :addresses, allow_destroy: false
|
|
1731
|
+
end
|
|
1732
|
+
|
|
1733
|
+
after do
|
|
1734
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1735
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1736
|
+
end
|
|
1737
|
+
|
|
1738
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
1739
|
+
|
|
1740
|
+
context "when passed a #{truth} with destroy" do
|
|
1741
|
+
|
|
1742
|
+
before do
|
|
1743
|
+
person.addresses_attributes =
|
|
1744
|
+
{
|
|
1745
|
+
"bar" => {
|
|
1746
|
+
"id" => address_one.id, "street" => "Maybachufer", "_destroy" => truth },
|
|
1747
|
+
"foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1748
|
+
}
|
|
1749
|
+
end
|
|
1750
|
+
|
|
1751
|
+
it "does not ignore the marked document" do
|
|
1752
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
1753
|
+
end
|
|
1754
|
+
|
|
1755
|
+
it "does not delete the unmarked document" do
|
|
1756
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
1757
|
+
end
|
|
1758
|
+
|
|
1759
|
+
it "does not add additional documents" do
|
|
1760
|
+
expect(person.addresses.size).to eq(2)
|
|
1761
|
+
end
|
|
1762
|
+
end
|
|
1763
|
+
end
|
|
1764
|
+
|
|
1765
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
1766
|
+
|
|
1767
|
+
context "when passed a #{falsehood} with destroy" do
|
|
1768
|
+
|
|
1769
|
+
before do
|
|
1770
|
+
person.addresses_attributes =
|
|
1771
|
+
{
|
|
1772
|
+
"bar" => { "id" => address_one.id, "_destroy" => falsehood },
|
|
1773
|
+
"foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1774
|
+
}
|
|
1775
|
+
end
|
|
1776
|
+
|
|
1777
|
+
it "does not delete the marked document" do
|
|
1778
|
+
expect(person.addresses.size).to eq(2)
|
|
1779
|
+
end
|
|
1780
|
+
|
|
1781
|
+
it "does not delete the unmarked document" do
|
|
1782
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
1783
|
+
end
|
|
1784
|
+
end
|
|
1785
|
+
end
|
|
1786
|
+
end
|
|
1787
|
+
|
|
1788
|
+
context "when allow_destroy is undefined" do
|
|
1789
|
+
|
|
1790
|
+
before do
|
|
1791
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1792
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1793
|
+
end
|
|
1794
|
+
|
|
1795
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
1796
|
+
|
|
1797
|
+
context "when passed a #{truth} with destroy" do
|
|
1798
|
+
|
|
1799
|
+
before do
|
|
1800
|
+
person.addresses_attributes =
|
|
1801
|
+
{
|
|
1802
|
+
"bar" => {
|
|
1803
|
+
"id" => address_one.id, "street" => "Maybachufer", "_destroy" => truth },
|
|
1804
|
+
"foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1805
|
+
}
|
|
1806
|
+
end
|
|
1807
|
+
|
|
1808
|
+
it "does not ignore the marked document" do
|
|
1809
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
1810
|
+
end
|
|
1811
|
+
|
|
1812
|
+
it "does not delete the unmarked document" do
|
|
1813
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
1814
|
+
end
|
|
1815
|
+
|
|
1816
|
+
it "does not add additional documents" do
|
|
1817
|
+
expect(person.addresses.size).to eq(2)
|
|
1818
|
+
end
|
|
1819
|
+
end
|
|
1820
|
+
end
|
|
1821
|
+
|
|
1822
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
1823
|
+
|
|
1824
|
+
context "when passed a #{falsehood} with destroy" do
|
|
1825
|
+
|
|
1826
|
+
before do
|
|
1827
|
+
person.addresses_attributes =
|
|
1828
|
+
{
|
|
1829
|
+
"bar" => { "id" => address_one.id, "_destroy" => falsehood },
|
|
1830
|
+
"foo" => { "id" => address_two.id, "street" => "Alexander Platz" }
|
|
1831
|
+
}
|
|
1832
|
+
end
|
|
1833
|
+
|
|
1834
|
+
it "does not delete the marked document" do
|
|
1835
|
+
expect(person.addresses.size).to eq(2)
|
|
1836
|
+
end
|
|
1837
|
+
|
|
1838
|
+
it "does not delete the unmarked document" do
|
|
1839
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
1840
|
+
end
|
|
1841
|
+
end
|
|
1842
|
+
end
|
|
1843
|
+
end
|
|
1844
|
+
end
|
|
1845
|
+
end
|
|
1846
|
+
end
|
|
1847
|
+
|
|
1848
|
+
context "when no ids are passed" do
|
|
1849
|
+
|
|
1850
|
+
context "when no destroy attributes are passed" do
|
|
1851
|
+
|
|
1852
|
+
before do
|
|
1853
|
+
person.addresses_attributes =
|
|
1854
|
+
{
|
|
1855
|
+
"4" => { "street" => "Maybachufer" },
|
|
1856
|
+
"1" => { "street" => "Frederichstrasse" },
|
|
1857
|
+
"2" => { "street" => "Alexander Platz" }
|
|
1858
|
+
}
|
|
1859
|
+
end
|
|
1860
|
+
|
|
1861
|
+
it "builds a new first document" do
|
|
1862
|
+
expect(person.addresses.first.street).to eq("Frederichstrasse")
|
|
1863
|
+
end
|
|
1864
|
+
|
|
1865
|
+
it "builds a new second document" do
|
|
1866
|
+
expect(person.addresses.second.street).to eq("Alexander Platz")
|
|
1867
|
+
end
|
|
1868
|
+
|
|
1869
|
+
it "builds a new third document" do
|
|
1870
|
+
expect(person.addresses.third.street).to eq("Maybachufer")
|
|
1871
|
+
end
|
|
1872
|
+
|
|
1873
|
+
it "does not add extra documents" do
|
|
1874
|
+
expect(person.addresses.size).to eq(3)
|
|
1875
|
+
end
|
|
1876
|
+
|
|
1877
|
+
it "adds the documents in the sorted hash key order" do
|
|
1878
|
+
expect(person.addresses.map(&:street)).to eq(
|
|
1879
|
+
[ "Frederichstrasse", "Alexander Platz", "Maybachufer" ]
|
|
1880
|
+
)
|
|
1881
|
+
end
|
|
1882
|
+
end
|
|
1883
|
+
|
|
1884
|
+
context "when a reject block is supplied" do
|
|
1885
|
+
|
|
1886
|
+
before do
|
|
1887
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1888
|
+
Person.accepts_nested_attributes_for \
|
|
1889
|
+
:addresses, reject_if: ->(attrs){ attrs["street"].blank? }
|
|
1890
|
+
end
|
|
1891
|
+
|
|
1892
|
+
after do
|
|
1893
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1894
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1895
|
+
end
|
|
1896
|
+
|
|
1897
|
+
context "when the attributes match" do
|
|
1898
|
+
|
|
1899
|
+
before do
|
|
1900
|
+
person.addresses_attributes =
|
|
1901
|
+
{ "3" => { "city" => "Berlin" } }
|
|
1902
|
+
end
|
|
1903
|
+
|
|
1904
|
+
it "does not add the new document" do
|
|
1905
|
+
expect(person.addresses).to be_empty
|
|
1906
|
+
end
|
|
1907
|
+
end
|
|
1908
|
+
|
|
1909
|
+
context "when the attributes do not match" do
|
|
1910
|
+
|
|
1911
|
+
before do
|
|
1912
|
+
person.addresses_attributes =
|
|
1913
|
+
{ "3" => { "street" => "Maybachufer" } }
|
|
1914
|
+
end
|
|
1915
|
+
|
|
1916
|
+
it "adds the new document" do
|
|
1917
|
+
expect(person.addresses.size).to eq(1)
|
|
1918
|
+
end
|
|
1919
|
+
|
|
1920
|
+
it "sets the correct attributes" do
|
|
1921
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
1922
|
+
end
|
|
1923
|
+
end
|
|
1924
|
+
end
|
|
1925
|
+
|
|
1926
|
+
context "when :reject_if => :all_blank is supplied" do
|
|
1927
|
+
|
|
1928
|
+
before do
|
|
1929
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1930
|
+
Person.accepts_nested_attributes_for \
|
|
1931
|
+
:addresses, reject_if: :all_blank
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
after do
|
|
1935
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1936
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1937
|
+
end
|
|
1938
|
+
|
|
1939
|
+
context "when all attributes are empty" do
|
|
1940
|
+
|
|
1941
|
+
before do
|
|
1942
|
+
person.addresses_attributes =
|
|
1943
|
+
{ "3" => { "city" => "" } }
|
|
1944
|
+
end
|
|
1945
|
+
|
|
1946
|
+
it "does not add the new document" do
|
|
1947
|
+
expect(person.addresses).to be_empty
|
|
1948
|
+
end
|
|
1949
|
+
end
|
|
1950
|
+
|
|
1951
|
+
context "when an attribute is not-empty" do
|
|
1952
|
+
|
|
1953
|
+
before do
|
|
1954
|
+
person.addresses_attributes =
|
|
1955
|
+
{ "3" => { "street" => "Maybachufer" } }
|
|
1956
|
+
end
|
|
1957
|
+
|
|
1958
|
+
it "adds the new document" do
|
|
1959
|
+
expect(person.addresses.size).to eq(1)
|
|
1960
|
+
end
|
|
1961
|
+
|
|
1962
|
+
it "sets the correct attributes" do
|
|
1963
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
1964
|
+
end
|
|
1965
|
+
end
|
|
1966
|
+
end
|
|
1967
|
+
|
|
1968
|
+
context "when destroy attributes are passed" do
|
|
1969
|
+
|
|
1970
|
+
context "when allow_destroy is true" do
|
|
1971
|
+
|
|
1972
|
+
before do
|
|
1973
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1974
|
+
Person.accepts_nested_attributes_for :addresses, allow_destroy: true
|
|
1975
|
+
end
|
|
1976
|
+
|
|
1977
|
+
after do
|
|
1978
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
1979
|
+
Person.accepts_nested_attributes_for :addresses
|
|
1980
|
+
end
|
|
1981
|
+
|
|
1982
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
1983
|
+
|
|
1984
|
+
context "when passed a #{truth} with destroy" do
|
|
1985
|
+
|
|
1986
|
+
before do
|
|
1987
|
+
person.addresses_attributes =
|
|
1988
|
+
{
|
|
1989
|
+
"bar" => { "street" => "Maybachufer", "_destroy" => truth },
|
|
1990
|
+
"foo" => { "street" => "Alexander Platz" }
|
|
1991
|
+
}
|
|
1992
|
+
end
|
|
1993
|
+
|
|
1994
|
+
it "ignores the marked document" do
|
|
1995
|
+
expect(person.addresses.size).to eq(1)
|
|
1996
|
+
end
|
|
1997
|
+
|
|
1998
|
+
it "adds the new unmarked document" do
|
|
1999
|
+
expect(person.addresses.first.street).to eq("Alexander Platz")
|
|
2000
|
+
end
|
|
2001
|
+
end
|
|
2002
|
+
end
|
|
2003
|
+
|
|
2004
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
2005
|
+
|
|
2006
|
+
context "when passed a #{falsehood} with destroy" do
|
|
2007
|
+
|
|
2008
|
+
before do
|
|
2009
|
+
person.addresses_attributes =
|
|
2010
|
+
{
|
|
2011
|
+
"0" => { "street" => "Maybachufer", "_destroy" => falsehood },
|
|
2012
|
+
"1" => { "street" => "Alexander Platz" }
|
|
2013
|
+
}
|
|
2014
|
+
end
|
|
2015
|
+
|
|
2016
|
+
it "adds the new marked document" do
|
|
2017
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
2018
|
+
end
|
|
2019
|
+
|
|
2020
|
+
it "adds the new unmarked document" do
|
|
2021
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
2022
|
+
end
|
|
2023
|
+
|
|
2024
|
+
it "does not add extra documents" do
|
|
2025
|
+
expect(person.addresses.size).to eq(2)
|
|
2026
|
+
end
|
|
2027
|
+
end
|
|
2028
|
+
end
|
|
2029
|
+
end
|
|
2030
|
+
|
|
2031
|
+
context "when allow destroy is false" do
|
|
2032
|
+
|
|
2033
|
+
before do
|
|
2034
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
2035
|
+
Person.accepts_nested_attributes_for :addresses, allow_destroy: false
|
|
2036
|
+
end
|
|
2037
|
+
|
|
2038
|
+
after do
|
|
2039
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
2040
|
+
Person.accepts_nested_attributes_for :addresses
|
|
2041
|
+
end
|
|
2042
|
+
|
|
2043
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
2044
|
+
|
|
2045
|
+
context "when passed a #{truth} with destroy" do
|
|
2046
|
+
|
|
2047
|
+
before do
|
|
2048
|
+
person.addresses_attributes =
|
|
2049
|
+
{
|
|
2050
|
+
"0" => { "street" => "Maybachufer", "_destroy" => truth },
|
|
2051
|
+
"1" => { "street" => "Alexander Platz" }
|
|
2052
|
+
}
|
|
2053
|
+
end
|
|
2054
|
+
|
|
2055
|
+
it "adds the marked document" do
|
|
2056
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
2057
|
+
end
|
|
2058
|
+
|
|
2059
|
+
it "adds the new unmarked document" do
|
|
2060
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
2061
|
+
end
|
|
2062
|
+
|
|
2063
|
+
it "adds the correct number of documents" do
|
|
2064
|
+
expect(person.addresses.size).to eq(2)
|
|
2065
|
+
end
|
|
2066
|
+
end
|
|
2067
|
+
end
|
|
2068
|
+
|
|
2069
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
2070
|
+
|
|
2071
|
+
context "when passed a #{falsehood} with destroy" do
|
|
2072
|
+
|
|
2073
|
+
before do
|
|
2074
|
+
person.addresses_attributes =
|
|
2075
|
+
{
|
|
2076
|
+
"0" => { "street" => "Maybachufer", "_destroy" => falsehood },
|
|
2077
|
+
"1" => { "street" => "Alexander Platz" }
|
|
2078
|
+
}
|
|
2079
|
+
end
|
|
2080
|
+
|
|
2081
|
+
it "adds the new marked document" do
|
|
2082
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
2083
|
+
end
|
|
2084
|
+
|
|
2085
|
+
it "adds the new unmarked document" do
|
|
2086
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
2087
|
+
end
|
|
2088
|
+
|
|
2089
|
+
it "does not add extra documents" do
|
|
2090
|
+
expect(person.addresses.size).to eq(2)
|
|
2091
|
+
end
|
|
2092
|
+
end
|
|
2093
|
+
end
|
|
2094
|
+
end
|
|
2095
|
+
|
|
2096
|
+
context "when allow destroy is not defined" do
|
|
2097
|
+
|
|
2098
|
+
before do
|
|
2099
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
2100
|
+
Person.accepts_nested_attributes_for :addresses
|
|
2101
|
+
end
|
|
2102
|
+
|
|
2103
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
2104
|
+
|
|
2105
|
+
context "when passed a #{truth} with destroy" do
|
|
2106
|
+
|
|
2107
|
+
before do
|
|
2108
|
+
person.addresses_attributes =
|
|
2109
|
+
{
|
|
2110
|
+
"0" => { "street" => "Maybachufer", "_destroy" => truth },
|
|
2111
|
+
"1" => { "street" => "Alexander Platz" }
|
|
2112
|
+
}
|
|
2113
|
+
end
|
|
2114
|
+
|
|
2115
|
+
it "adds the marked document" do
|
|
2116
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
2117
|
+
end
|
|
2118
|
+
|
|
2119
|
+
it "adds the new unmarked document" do
|
|
2120
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
2121
|
+
end
|
|
2122
|
+
|
|
2123
|
+
it "adds the correct number of documents" do
|
|
2124
|
+
expect(person.addresses.size).to eq(2)
|
|
2125
|
+
end
|
|
2126
|
+
end
|
|
2127
|
+
end
|
|
2128
|
+
|
|
2129
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
2130
|
+
|
|
2131
|
+
context "when passed a #{falsehood} with destroy" do
|
|
2132
|
+
|
|
2133
|
+
before do
|
|
2134
|
+
person.addresses_attributes =
|
|
2135
|
+
{
|
|
2136
|
+
"0" => { "street" => "Maybachufer", "_destroy" => falsehood },
|
|
2137
|
+
"1" => { "street" => "Alexander Platz" }
|
|
2138
|
+
}
|
|
2139
|
+
end
|
|
2140
|
+
|
|
2141
|
+
it "adds the new marked document" do
|
|
2142
|
+
expect(person.addresses.first.street).to eq("Maybachufer")
|
|
2143
|
+
end
|
|
2144
|
+
|
|
2145
|
+
it "adds the new unmarked document" do
|
|
2146
|
+
expect(person.addresses.last.street).to eq("Alexander Platz")
|
|
2147
|
+
end
|
|
2148
|
+
|
|
2149
|
+
it "does not add extra documents" do
|
|
2150
|
+
expect(person.addresses.size).to eq(2)
|
|
2151
|
+
end
|
|
2152
|
+
end
|
|
2153
|
+
end
|
|
2154
|
+
end
|
|
2155
|
+
end
|
|
2156
|
+
|
|
2157
|
+
context "when 'reject_if: :all_blank' and 'allow_destroy: true' are specified" do
|
|
2158
|
+
|
|
2159
|
+
before do
|
|
2160
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
2161
|
+
Person.accepts_nested_attributes_for \
|
|
2162
|
+
:addresses, reject_if: :all_blank, allow_destroy: true
|
|
2163
|
+
end
|
|
2164
|
+
|
|
2165
|
+
after do
|
|
2166
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
2167
|
+
Person.accepts_nested_attributes_for :addresses
|
|
2168
|
+
end
|
|
2169
|
+
|
|
2170
|
+
context "when all attributes are blank and _destroy has a truthy, non-blank value" do
|
|
2171
|
+
|
|
2172
|
+
before do
|
|
2173
|
+
person.addresses_attributes =
|
|
2174
|
+
{ "3" => { last_name: "", _destroy: "0" } }
|
|
2175
|
+
end
|
|
2176
|
+
|
|
2177
|
+
it "does not add the document" do
|
|
2178
|
+
expect(person.addresses).to be_empty
|
|
2179
|
+
end
|
|
2180
|
+
end
|
|
2181
|
+
end
|
|
2182
|
+
end
|
|
2183
|
+
|
|
2184
|
+
context "when the nested document is invalid" do
|
|
2185
|
+
|
|
2186
|
+
before do
|
|
2187
|
+
Person.validates_associated(:addresses)
|
|
2188
|
+
end
|
|
2189
|
+
|
|
2190
|
+
after do
|
|
2191
|
+
Person.reset_callbacks(:validate)
|
|
2192
|
+
end
|
|
2193
|
+
|
|
2194
|
+
before do
|
|
2195
|
+
person.addresses_attributes = {
|
|
2196
|
+
"0" => { street: '123' }
|
|
2197
|
+
}
|
|
2198
|
+
end
|
|
2199
|
+
|
|
2200
|
+
it "propagates invalidity to parent" do
|
|
2201
|
+
expect(person.addresses.first).to_not be_valid
|
|
2202
|
+
expect(person).to_not be_valid
|
|
2203
|
+
end
|
|
2204
|
+
end
|
|
2205
|
+
|
|
2206
|
+
context "when a type is passed" do
|
|
2207
|
+
|
|
2208
|
+
let(:canvas) do
|
|
2209
|
+
Canvas.new
|
|
2210
|
+
end
|
|
2211
|
+
|
|
2212
|
+
before do
|
|
2213
|
+
Canvas.send(:undef_method, :shapes_attributes=)
|
|
2214
|
+
Canvas.accepts_nested_attributes_for :shapes
|
|
2215
|
+
canvas.shapes_attributes =
|
|
2216
|
+
{
|
|
2217
|
+
"foo" => { "_type" => "Square" },
|
|
2218
|
+
"bar" => { "_type" => "Circle" }
|
|
2219
|
+
}
|
|
2220
|
+
end
|
|
2221
|
+
|
|
2222
|
+
it "instantiates an object of the given type" do
|
|
2223
|
+
expect(canvas.shapes.map(&:class)).to eq([Square, Circle])
|
|
2224
|
+
end
|
|
2225
|
+
end
|
|
2226
|
+
end
|
|
2227
|
+
|
|
2228
|
+
context "when the relation is a references one" do
|
|
2229
|
+
|
|
2230
|
+
let(:person) do
|
|
2231
|
+
Person.new
|
|
2232
|
+
end
|
|
2233
|
+
|
|
2234
|
+
context "when a reject proc is specified" do
|
|
2235
|
+
|
|
2236
|
+
before do
|
|
2237
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2238
|
+
Person.accepts_nested_attributes_for \
|
|
2239
|
+
:game, reject_if: ->(attrs){ attrs[:name].blank? }
|
|
2240
|
+
end
|
|
2241
|
+
|
|
2242
|
+
after do
|
|
2243
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2244
|
+
Person.accepts_nested_attributes_for :game
|
|
2245
|
+
end
|
|
2246
|
+
|
|
2247
|
+
context "when the attributes match" do
|
|
2248
|
+
|
|
2249
|
+
before do
|
|
2250
|
+
person.game_attributes = { score: 10 }
|
|
2251
|
+
end
|
|
2252
|
+
|
|
2253
|
+
it "does not add the document" do
|
|
2254
|
+
expect(person.game).to be_nil
|
|
2255
|
+
end
|
|
2256
|
+
end
|
|
2257
|
+
|
|
2258
|
+
context "when the attributes do not match" do
|
|
2259
|
+
|
|
2260
|
+
before do
|
|
2261
|
+
person.game_attributes = { name: "Tron" }
|
|
2262
|
+
end
|
|
2263
|
+
|
|
2264
|
+
it "adds the document" do
|
|
2265
|
+
expect(person.game.name).to eq("Tron")
|
|
2266
|
+
end
|
|
2267
|
+
end
|
|
2268
|
+
end
|
|
2269
|
+
|
|
2270
|
+
context "when reject_if => :all_blank is specified" do
|
|
2271
|
+
|
|
2272
|
+
before do
|
|
2273
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2274
|
+
Person.accepts_nested_attributes_for \
|
|
2275
|
+
:game, reject_if: :all_blank
|
|
2276
|
+
end
|
|
2277
|
+
|
|
2278
|
+
after do
|
|
2279
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2280
|
+
Person.accepts_nested_attributes_for :game
|
|
2281
|
+
end
|
|
2282
|
+
|
|
2283
|
+
context "when all attributes are empty" do
|
|
2284
|
+
|
|
2285
|
+
before do
|
|
2286
|
+
person.game_attributes = { score: nil }
|
|
2287
|
+
end
|
|
2288
|
+
|
|
2289
|
+
it "does not add the document" do
|
|
2290
|
+
expect(person.game).to be_nil
|
|
2291
|
+
end
|
|
2292
|
+
end
|
|
2293
|
+
|
|
2294
|
+
context "when an attribute is non-empty" do
|
|
2295
|
+
|
|
2296
|
+
before do
|
|
2297
|
+
person.game_attributes = { name: "Tron" }
|
|
2298
|
+
end
|
|
2299
|
+
|
|
2300
|
+
it "adds the document" do
|
|
2301
|
+
expect(person.game.name).to eq("Tron")
|
|
2302
|
+
end
|
|
2303
|
+
end
|
|
2304
|
+
end
|
|
2305
|
+
|
|
2306
|
+
context "when no id has been passed" do
|
|
2307
|
+
|
|
2308
|
+
context "with no destroy attribute" do
|
|
2309
|
+
|
|
2310
|
+
before do
|
|
2311
|
+
person.game_attributes = { name: "Tron" }
|
|
2312
|
+
end
|
|
2313
|
+
|
|
2314
|
+
it "builds a new document" do
|
|
2315
|
+
expect(person.game.name).to eq("Tron")
|
|
2316
|
+
end
|
|
2317
|
+
end
|
|
2318
|
+
|
|
2319
|
+
context "with a destroy attribute" do
|
|
2320
|
+
|
|
2321
|
+
context "when allow_destroy is true" do
|
|
2322
|
+
|
|
2323
|
+
before do
|
|
2324
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2325
|
+
Person.accepts_nested_attributes_for :game, allow_destroy: true
|
|
2326
|
+
end
|
|
2327
|
+
|
|
2328
|
+
after do
|
|
2329
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2330
|
+
Person.accepts_nested_attributes_for :game
|
|
2331
|
+
end
|
|
2332
|
+
|
|
2333
|
+
before do
|
|
2334
|
+
person.game_attributes = { name: "Tron", _destroy: "1" }
|
|
2335
|
+
end
|
|
2336
|
+
|
|
2337
|
+
it "does not build the document" do
|
|
2338
|
+
expect(person.game).to be_nil
|
|
2339
|
+
end
|
|
2340
|
+
end
|
|
2341
|
+
|
|
2342
|
+
context "when allow_destroy is false" do
|
|
2343
|
+
|
|
2344
|
+
before do
|
|
2345
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2346
|
+
Person.accepts_nested_attributes_for :game, allow_destroy: false
|
|
2347
|
+
end
|
|
2348
|
+
|
|
2349
|
+
after do
|
|
2350
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2351
|
+
Person.accepts_nested_attributes_for :game
|
|
2352
|
+
end
|
|
2353
|
+
|
|
2354
|
+
before do
|
|
2355
|
+
person.game_attributes = { name: "Tron", _destroy: "1" }
|
|
2356
|
+
end
|
|
2357
|
+
|
|
2358
|
+
it "builds the document" do
|
|
2359
|
+
expect(person.game.name).to eq("Tron")
|
|
2360
|
+
end
|
|
2361
|
+
end
|
|
2362
|
+
end
|
|
2363
|
+
|
|
2364
|
+
context "with empty attributes" do
|
|
2365
|
+
|
|
2366
|
+
before do
|
|
2367
|
+
person.game_attributes = {}
|
|
2368
|
+
end
|
|
2369
|
+
|
|
2370
|
+
it "does not build the document" do
|
|
2371
|
+
expect(person.game).to be_nil
|
|
2372
|
+
end
|
|
2373
|
+
end
|
|
2374
|
+
|
|
2375
|
+
context "when there is an existing document" do
|
|
2376
|
+
|
|
2377
|
+
context "with no destroy attribute" do
|
|
2378
|
+
|
|
2379
|
+
before do
|
|
2380
|
+
person.game = Game.new(name: "Tron")
|
|
2381
|
+
person.game_attributes = { name: "Pong" }
|
|
2382
|
+
end
|
|
2383
|
+
|
|
2384
|
+
it "replaces the document" do
|
|
2385
|
+
expect(person.game.name).to eq("Pong")
|
|
2386
|
+
end
|
|
2387
|
+
end
|
|
2388
|
+
|
|
2389
|
+
context "when updating attributes" do
|
|
2390
|
+
|
|
2391
|
+
let!(:pizza) do
|
|
2392
|
+
Pizza.create(name: "large")
|
|
2393
|
+
end
|
|
2394
|
+
|
|
2395
|
+
before do
|
|
2396
|
+
pizza.topping = Topping.create!(name: "cheese")
|
|
2397
|
+
pizza.update_attributes!(topping_attributes: { name: "onions" })
|
|
2398
|
+
end
|
|
2399
|
+
|
|
2400
|
+
it "persists the attribute changes" do
|
|
2401
|
+
expect(pizza.reload.topping.name).to eq("onions")
|
|
2402
|
+
end
|
|
2403
|
+
end
|
|
2404
|
+
|
|
2405
|
+
context "with a destroy attribute" do
|
|
2406
|
+
|
|
2407
|
+
context "when allow_destroy is true" do
|
|
2408
|
+
|
|
2409
|
+
before do
|
|
2410
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2411
|
+
Person.accepts_nested_attributes_for :game, allow_destroy: true
|
|
2412
|
+
end
|
|
2413
|
+
|
|
2414
|
+
after do
|
|
2415
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2416
|
+
Person.accepts_nested_attributes_for :game
|
|
2417
|
+
end
|
|
2418
|
+
|
|
2419
|
+
before do
|
|
2420
|
+
person.game = Game.new(name: "Tron")
|
|
2421
|
+
person.game_attributes = { name: "Pong", _destroy: "1" }
|
|
2422
|
+
end
|
|
2423
|
+
|
|
2424
|
+
it "does not replace the document" do
|
|
2425
|
+
expect(person.game.name).to eq("Tron")
|
|
2426
|
+
end
|
|
2427
|
+
end
|
|
2428
|
+
|
|
2429
|
+
context "when allow_destroy is false" do
|
|
2430
|
+
|
|
2431
|
+
before do
|
|
2432
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2433
|
+
Person.accepts_nested_attributes_for :game, allow_destroy: false
|
|
2434
|
+
end
|
|
2435
|
+
|
|
2436
|
+
after do
|
|
2437
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2438
|
+
Person.accepts_nested_attributes_for :game
|
|
2439
|
+
end
|
|
2440
|
+
|
|
2441
|
+
before do
|
|
2442
|
+
person.game = Game.new(name: "Tron")
|
|
2443
|
+
person.game_attributes = { name: "Pong", _destroy: "1" }
|
|
2444
|
+
end
|
|
2445
|
+
|
|
2446
|
+
it "replaces the document" do
|
|
2447
|
+
expect(person.game.name).to eq("Pong")
|
|
2448
|
+
end
|
|
2449
|
+
end
|
|
2450
|
+
end
|
|
2451
|
+
end
|
|
2452
|
+
end
|
|
2453
|
+
|
|
2454
|
+
context "when an id is passed" do
|
|
2455
|
+
|
|
2456
|
+
context "when there is an existing record" do
|
|
2457
|
+
|
|
2458
|
+
let(:game) do
|
|
2459
|
+
Game.new(name: "Tron")
|
|
2460
|
+
end
|
|
2461
|
+
|
|
2462
|
+
before do
|
|
2463
|
+
person.game = game
|
|
2464
|
+
end
|
|
2465
|
+
|
|
2466
|
+
context "when the id matches" do
|
|
2467
|
+
|
|
2468
|
+
context "when passed keys as symbols" do
|
|
2469
|
+
|
|
2470
|
+
before do
|
|
2471
|
+
person.game_attributes =
|
|
2472
|
+
{ id: game.id, name: "Pong" }
|
|
2473
|
+
end
|
|
2474
|
+
|
|
2475
|
+
it "updates the existing document" do
|
|
2476
|
+
expect(person.game.name).to eq("Pong")
|
|
2477
|
+
end
|
|
2478
|
+
end
|
|
2479
|
+
|
|
2480
|
+
context "when passed keys as strings" do
|
|
2481
|
+
|
|
2482
|
+
before do
|
|
2483
|
+
person.game_attributes =
|
|
2484
|
+
{ "id" => game.id, "name" => "Pong" }
|
|
2485
|
+
end
|
|
2486
|
+
|
|
2487
|
+
it "updates the existing document" do
|
|
2488
|
+
expect(person.game.name).to eq("Pong")
|
|
2489
|
+
end
|
|
2490
|
+
end
|
|
2491
|
+
|
|
2492
|
+
context "when allow_destroy is true" do
|
|
2493
|
+
|
|
2494
|
+
before do
|
|
2495
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2496
|
+
Person.accepts_nested_attributes_for :game, allow_destroy: true
|
|
2497
|
+
end
|
|
2498
|
+
|
|
2499
|
+
after do
|
|
2500
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2501
|
+
Person.accepts_nested_attributes_for :game
|
|
2502
|
+
end
|
|
2503
|
+
|
|
2504
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
2505
|
+
|
|
2506
|
+
context "when passed #{truth} with destroy" do
|
|
2507
|
+
|
|
2508
|
+
before do
|
|
2509
|
+
person.game_attributes =
|
|
2510
|
+
{ id: game.id, _destroy: truth }
|
|
2511
|
+
end
|
|
2512
|
+
|
|
2513
|
+
it "destroys the existing document" do
|
|
2514
|
+
expect(person.game).to be_nil
|
|
2515
|
+
end
|
|
2516
|
+
end
|
|
2517
|
+
end
|
|
2518
|
+
|
|
2519
|
+
[ nil, 0, "0", false, "false" ].each do |falsehood|
|
|
2520
|
+
|
|
2521
|
+
context "when passed #{falsehood} with destroy" do
|
|
2522
|
+
|
|
2523
|
+
before do
|
|
2524
|
+
person.game_attributes =
|
|
2525
|
+
{ id: game.id, _destroy: falsehood }
|
|
2526
|
+
end
|
|
2527
|
+
|
|
2528
|
+
it "does not destroy the existing document" do
|
|
2529
|
+
expect(person.game).to eq(game)
|
|
2530
|
+
end
|
|
2531
|
+
end
|
|
2532
|
+
end
|
|
2533
|
+
end
|
|
2534
|
+
|
|
2535
|
+
context "when allow destroy is false" do
|
|
2536
|
+
|
|
2537
|
+
before do
|
|
2538
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2539
|
+
Person.accepts_nested_attributes_for :game, allow_destroy: false
|
|
2540
|
+
end
|
|
2541
|
+
|
|
2542
|
+
after do
|
|
2543
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2544
|
+
Person.accepts_nested_attributes_for :game
|
|
2545
|
+
end
|
|
2546
|
+
|
|
2547
|
+
context "when a destroy attribute is passed" do
|
|
2548
|
+
|
|
2549
|
+
before do
|
|
2550
|
+
person.game_attributes =
|
|
2551
|
+
{ id: game.id, _destroy: true }
|
|
2552
|
+
end
|
|
2553
|
+
|
|
2554
|
+
it "does not destroy the document" do
|
|
2555
|
+
expect(person.game).to eq(game)
|
|
2556
|
+
end
|
|
2557
|
+
end
|
|
2558
|
+
end
|
|
2559
|
+
|
|
2560
|
+
context "when update only is true" do
|
|
2561
|
+
|
|
2562
|
+
before do
|
|
2563
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2564
|
+
Person.accepts_nested_attributes_for \
|
|
2565
|
+
:game,
|
|
2566
|
+
update_only: true,
|
|
2567
|
+
allow_destroy: true
|
|
2568
|
+
end
|
|
2569
|
+
|
|
2570
|
+
after do
|
|
2571
|
+
Person.send(:undef_method, :game_attributes=)
|
|
2572
|
+
Person.accepts_nested_attributes_for :game
|
|
2573
|
+
end
|
|
2574
|
+
|
|
2575
|
+
context "when the id matches" do
|
|
2576
|
+
|
|
2577
|
+
before do
|
|
2578
|
+
person.game_attributes =
|
|
2579
|
+
{ id: game.id, name: "Donkey Kong" }
|
|
2580
|
+
end
|
|
2581
|
+
|
|
2582
|
+
it "updates the existing document" do
|
|
2583
|
+
expect(person.game.name).to eq("Donkey Kong")
|
|
2584
|
+
end
|
|
2585
|
+
end
|
|
2586
|
+
|
|
2587
|
+
context "when the id does not match" do
|
|
2588
|
+
|
|
2589
|
+
before do
|
|
2590
|
+
person.game_attributes =
|
|
2591
|
+
{ id: BSON::ObjectId.new.to_s, name: "Pong" }
|
|
2592
|
+
end
|
|
2593
|
+
|
|
2594
|
+
it "updates the existing document" do
|
|
2595
|
+
expect(person.game.name).to eq("Pong")
|
|
2596
|
+
end
|
|
2597
|
+
end
|
|
2598
|
+
|
|
2599
|
+
context "when passed a destroy truth" do
|
|
2600
|
+
|
|
2601
|
+
before do
|
|
2602
|
+
person.game_attributes =
|
|
2603
|
+
{ id: game.id, _destroy: true }
|
|
2604
|
+
end
|
|
2605
|
+
|
|
2606
|
+
it "destroys the existing document" do
|
|
2607
|
+
expect(person.game).to be_nil
|
|
2608
|
+
end
|
|
2609
|
+
end
|
|
2610
|
+
end
|
|
2611
|
+
end
|
|
2612
|
+
end
|
|
2613
|
+
end
|
|
2614
|
+
|
|
2615
|
+
context "when the nested document is invalid" do
|
|
2616
|
+
|
|
2617
|
+
before do
|
|
2618
|
+
Person.validates_associated(:game)
|
|
2619
|
+
end
|
|
2620
|
+
|
|
2621
|
+
after do
|
|
2622
|
+
Person.reset_callbacks(:validate)
|
|
2623
|
+
end
|
|
2624
|
+
|
|
2625
|
+
before do
|
|
2626
|
+
person.game_attributes = { name: '$$$' }
|
|
2627
|
+
end
|
|
2628
|
+
|
|
2629
|
+
it "propagates invalidity to parent" do
|
|
2630
|
+
expect(person.game).to_not be_valid
|
|
2631
|
+
expect(person).to_not be_valid
|
|
2632
|
+
end
|
|
2633
|
+
end
|
|
2634
|
+
|
|
2635
|
+
context "when a type is passed" do
|
|
2636
|
+
|
|
2637
|
+
let(:driver) do
|
|
2638
|
+
Driver.new
|
|
2639
|
+
end
|
|
2640
|
+
|
|
2641
|
+
before do
|
|
2642
|
+
Driver.send(:undef_method, :vehicle_attributes=)
|
|
2643
|
+
Driver.accepts_nested_attributes_for :vehicle
|
|
2644
|
+
driver.vehicle_attributes = { "_type" => "Truck" }
|
|
2645
|
+
end
|
|
2646
|
+
|
|
2647
|
+
it "instantiates an object of the given type" do
|
|
2648
|
+
expect(driver.vehicle.class).to eq(Truck)
|
|
2649
|
+
end
|
|
2650
|
+
end
|
|
2651
|
+
end
|
|
2652
|
+
|
|
2653
|
+
context "when the relation is referenced in" do
|
|
2654
|
+
|
|
2655
|
+
context "when the child is new" do
|
|
2656
|
+
|
|
2657
|
+
let(:game) do
|
|
2658
|
+
Game.new
|
|
2659
|
+
end
|
|
2660
|
+
|
|
2661
|
+
context "when no id has been passed" do
|
|
2662
|
+
|
|
2663
|
+
context "when no destroy attribute passed" do
|
|
2664
|
+
|
|
2665
|
+
before do
|
|
2666
|
+
game.person_attributes = { title: "Sir" }
|
|
2667
|
+
end
|
|
2668
|
+
|
|
2669
|
+
it "builds a new document" do
|
|
2670
|
+
expect(game.person.title).to eq("Sir")
|
|
2671
|
+
end
|
|
2672
|
+
|
|
2673
|
+
end
|
|
2674
|
+
|
|
2675
|
+
context "when a destroy attribute is passed" do
|
|
2676
|
+
|
|
2677
|
+
context "when allow_destroy is true" do
|
|
2678
|
+
|
|
2679
|
+
before do
|
|
2680
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2681
|
+
Game.accepts_nested_attributes_for :person, allow_destroy: true
|
|
2682
|
+
end
|
|
2683
|
+
|
|
2684
|
+
after do
|
|
2685
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2686
|
+
Game.accepts_nested_attributes_for :person
|
|
2687
|
+
end
|
|
2688
|
+
|
|
2689
|
+
before do
|
|
2690
|
+
game.person_attributes = { title: "Sir", _destroy: 1 }
|
|
2691
|
+
end
|
|
2692
|
+
|
|
2693
|
+
it "does not build a new document" do
|
|
2694
|
+
expect(game.person).to be_nil
|
|
2695
|
+
end
|
|
2696
|
+
end
|
|
2697
|
+
|
|
2698
|
+
context "when allow_destroy is false" do
|
|
2699
|
+
|
|
2700
|
+
before do
|
|
2701
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2702
|
+
Game.accepts_nested_attributes_for :person, allow_destroy: false
|
|
2703
|
+
end
|
|
2704
|
+
|
|
2705
|
+
after do
|
|
2706
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2707
|
+
Game.accepts_nested_attributes_for :person
|
|
2708
|
+
end
|
|
2709
|
+
|
|
2710
|
+
before do
|
|
2711
|
+
game.person_attributes = { title: "Sir", _destroy: 1 }
|
|
2712
|
+
end
|
|
2713
|
+
|
|
2714
|
+
it "builds a new document" do
|
|
2715
|
+
expect(game.person.title).to eq("Sir")
|
|
2716
|
+
end
|
|
2717
|
+
end
|
|
2718
|
+
end
|
|
2719
|
+
end
|
|
2720
|
+
|
|
2721
|
+
context "when an id has been passed" do
|
|
2722
|
+
|
|
2723
|
+
let(:person) do
|
|
2724
|
+
Person.new
|
|
2725
|
+
end
|
|
2726
|
+
|
|
2727
|
+
context "when no destroy attribute passed" do
|
|
2728
|
+
|
|
2729
|
+
context "when the id matches" do
|
|
2730
|
+
|
|
2731
|
+
before do
|
|
2732
|
+
game.person_attributes = { id: person.id, title: "Sir" }
|
|
2733
|
+
end
|
|
2734
|
+
|
|
2735
|
+
it "updates the existing document" do
|
|
2736
|
+
expect(game.person.title).to eq("Sir")
|
|
2737
|
+
end
|
|
2738
|
+
end
|
|
2739
|
+
end
|
|
2740
|
+
|
|
2741
|
+
context "when there is an existing document" do
|
|
2742
|
+
|
|
2743
|
+
before do
|
|
2744
|
+
game.person = person
|
|
2745
|
+
end
|
|
2746
|
+
|
|
2747
|
+
context "when allow destroy is true" do
|
|
2748
|
+
|
|
2749
|
+
before do
|
|
2750
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2751
|
+
Game.accepts_nested_attributes_for :person, allow_destroy: true
|
|
2752
|
+
end
|
|
2753
|
+
|
|
2754
|
+
after do
|
|
2755
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2756
|
+
Game.accepts_nested_attributes_for :person
|
|
2757
|
+
end
|
|
2758
|
+
|
|
2759
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
2760
|
+
|
|
2761
|
+
context "when passed #{truth} with destroy" do
|
|
2762
|
+
|
|
2763
|
+
before do
|
|
2764
|
+
game.person_attributes =
|
|
2765
|
+
{ id: person.id, _destroy: truth }
|
|
2766
|
+
end
|
|
2767
|
+
|
|
2768
|
+
it "destroys the existing document" do
|
|
2769
|
+
expect(game.person).to be_nil
|
|
2770
|
+
end
|
|
2771
|
+
end
|
|
2772
|
+
end
|
|
2773
|
+
|
|
2774
|
+
[ nil, 0, "0", false, "false" ].each do |falsehood|
|
|
2775
|
+
|
|
2776
|
+
context "when passed #{falsehood} with destroy" do
|
|
2777
|
+
|
|
2778
|
+
before do
|
|
2779
|
+
game.person_attributes =
|
|
2780
|
+
{ id: person.id, _destroy: falsehood }
|
|
2781
|
+
end
|
|
2782
|
+
|
|
2783
|
+
it "does not destroy the existing document" do
|
|
2784
|
+
expect(game.person).to eq(person)
|
|
2785
|
+
end
|
|
2786
|
+
end
|
|
2787
|
+
end
|
|
2788
|
+
end
|
|
2789
|
+
|
|
2790
|
+
context "when allow destroy is false" do
|
|
2791
|
+
|
|
2792
|
+
before do
|
|
2793
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2794
|
+
Game.accepts_nested_attributes_for :person, allow_destroy: false
|
|
2795
|
+
end
|
|
2796
|
+
|
|
2797
|
+
after do
|
|
2798
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2799
|
+
Game.accepts_nested_attributes_for :person
|
|
2800
|
+
end
|
|
2801
|
+
|
|
2802
|
+
context "when a destroy attribute is passed" do
|
|
2803
|
+
|
|
2804
|
+
before do
|
|
2805
|
+
game.person_attributes =
|
|
2806
|
+
{ id: person.id, _destroy: true }
|
|
2807
|
+
end
|
|
2808
|
+
|
|
2809
|
+
it "does not delete the document" do
|
|
2810
|
+
expect(game.person).to eq(person)
|
|
2811
|
+
end
|
|
2812
|
+
end
|
|
2813
|
+
end
|
|
2814
|
+
|
|
2815
|
+
context "when update only is true" do
|
|
2816
|
+
|
|
2817
|
+
before do
|
|
2818
|
+
Game.send(:undef_method, :person_attributes=)
|
|
2819
|
+
Game.accepts_nested_attributes_for \
|
|
2820
|
+
:person,
|
|
2821
|
+
update_only: true,
|
|
2822
|
+
allow_destroy: true
|
|
2823
|
+
end
|
|
2824
|
+
|
|
2825
|
+
context "when the id matches" do
|
|
2826
|
+
|
|
2827
|
+
before do
|
|
2828
|
+
game.person_attributes =
|
|
2829
|
+
{ id: person.id, title: "Madam" }
|
|
2830
|
+
end
|
|
2831
|
+
|
|
2832
|
+
it "updates the existing document" do
|
|
2833
|
+
expect(game.person.title).to eq("Madam")
|
|
2834
|
+
end
|
|
2835
|
+
end
|
|
2836
|
+
|
|
2837
|
+
context "when the id does not match" do
|
|
2838
|
+
|
|
2839
|
+
before do
|
|
2840
|
+
game.person_attributes =
|
|
2841
|
+
{ id: BSON::ObjectId.new.to_s, title: "Madam" }
|
|
2842
|
+
end
|
|
2843
|
+
|
|
2844
|
+
it "updates the existing document" do
|
|
2845
|
+
expect(game.person.title).to eq("Madam")
|
|
2846
|
+
end
|
|
2847
|
+
end
|
|
2848
|
+
|
|
2849
|
+
context "when passed a destroy truth" do
|
|
2850
|
+
|
|
2851
|
+
before do
|
|
2852
|
+
game.person_attributes =
|
|
2853
|
+
{ id: person.id, title: "Madam", _destroy: "true" }
|
|
2854
|
+
end
|
|
2855
|
+
|
|
2856
|
+
it "deletes the existing document" do
|
|
2857
|
+
expect(game.person).to be_nil
|
|
2858
|
+
end
|
|
2859
|
+
end
|
|
2860
|
+
end
|
|
2861
|
+
end
|
|
2862
|
+
end
|
|
2863
|
+
|
|
2864
|
+
context "when the nested document is invalid" do
|
|
2865
|
+
|
|
2866
|
+
before do
|
|
2867
|
+
Person.validates_format_of :ssn, without: /\$\$\$/
|
|
2868
|
+
end
|
|
2869
|
+
|
|
2870
|
+
after do
|
|
2871
|
+
Person.reset_callbacks(:validate)
|
|
2872
|
+
end
|
|
2873
|
+
|
|
2874
|
+
before do
|
|
2875
|
+
game.person_attributes = { ssn: '$$$' }
|
|
2876
|
+
end
|
|
2877
|
+
|
|
2878
|
+
it "propagates invalidity to parent" do
|
|
2879
|
+
expect(game.person).to_not be_valid
|
|
2880
|
+
expect(game).to_not be_valid
|
|
2881
|
+
end
|
|
2882
|
+
end
|
|
2883
|
+
end
|
|
2884
|
+
|
|
2885
|
+
context "when a type is passed" do
|
|
2886
|
+
|
|
2887
|
+
let(:vehicle) do
|
|
2888
|
+
Vehicle.new
|
|
2889
|
+
end
|
|
2890
|
+
|
|
2891
|
+
before do
|
|
2892
|
+
Vehicle.send(:undef_method, :driver_attributes=)
|
|
2893
|
+
Vehicle.accepts_nested_attributes_for :driver
|
|
2894
|
+
vehicle.driver_attributes = { "_type" => "Learner" }
|
|
2895
|
+
end
|
|
2896
|
+
|
|
2897
|
+
it "instantiates an object of the given type" do
|
|
2898
|
+
expect(vehicle.driver.class).to eq(Learner)
|
|
2899
|
+
end
|
|
2900
|
+
end
|
|
2901
|
+
end
|
|
2902
|
+
|
|
2903
|
+
context "when the relation is a references many" do
|
|
2904
|
+
|
|
2905
|
+
let(:person) do
|
|
2906
|
+
Person.new
|
|
2907
|
+
end
|
|
2908
|
+
|
|
2909
|
+
let(:post_one) do
|
|
2910
|
+
Post.new(title: "First post")
|
|
2911
|
+
end
|
|
2912
|
+
|
|
2913
|
+
let(:post_two) do
|
|
2914
|
+
Post.new(title: "First response")
|
|
2915
|
+
end
|
|
2916
|
+
|
|
2917
|
+
context "when a limit is specified" do
|
|
2918
|
+
|
|
2919
|
+
before do
|
|
2920
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
2921
|
+
Person.accepts_nested_attributes_for :posts, limit: 2
|
|
2922
|
+
end
|
|
2923
|
+
|
|
2924
|
+
after do
|
|
2925
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
2926
|
+
Person.accepts_nested_attributes_for :posts
|
|
2927
|
+
end
|
|
2928
|
+
|
|
2929
|
+
context "when more are provided than the limit" do
|
|
2930
|
+
|
|
2931
|
+
let(:attributes) do
|
|
2932
|
+
{
|
|
2933
|
+
"foo" => { "title" => "First" },
|
|
2934
|
+
"bar" => { "title" => "Second" },
|
|
2935
|
+
"baz" => { "title" => "Third" }
|
|
2936
|
+
}
|
|
2937
|
+
end
|
|
2938
|
+
|
|
2939
|
+
it "raises an error" do
|
|
2940
|
+
expect {
|
|
2941
|
+
person.posts_attributes = attributes
|
|
2942
|
+
}.to raise_error(Mongoid::Errors::TooManyNestedAttributeRecords)
|
|
2943
|
+
end
|
|
2944
|
+
end
|
|
2945
|
+
|
|
2946
|
+
context "when less are provided than the limit" do
|
|
2947
|
+
|
|
2948
|
+
let(:attributes) do
|
|
2949
|
+
{
|
|
2950
|
+
"foo" => { "title" => "First" },
|
|
2951
|
+
"bar" => { "title" => "Second" }
|
|
2952
|
+
}
|
|
2953
|
+
end
|
|
2954
|
+
|
|
2955
|
+
before do
|
|
2956
|
+
person.posts_attributes = attributes
|
|
2957
|
+
end
|
|
2958
|
+
|
|
2959
|
+
it "sets the documents on the relation" do
|
|
2960
|
+
expect(person.posts.size).to eq(2)
|
|
2961
|
+
end
|
|
2962
|
+
|
|
2963
|
+
it "does not persist the new documents" do
|
|
2964
|
+
expect(person.posts.count).to eq(0)
|
|
2965
|
+
end
|
|
2966
|
+
end
|
|
2967
|
+
end
|
|
2968
|
+
|
|
2969
|
+
context "when ids are passed" do
|
|
2970
|
+
|
|
2971
|
+
let(:person) do
|
|
2972
|
+
Person.create!
|
|
2973
|
+
end
|
|
2974
|
+
|
|
2975
|
+
before do
|
|
2976
|
+
person.posts << [ post_one, post_two ]
|
|
2977
|
+
end
|
|
2978
|
+
|
|
2979
|
+
context "when no destroy attributes are passed" do
|
|
2980
|
+
|
|
2981
|
+
context "when the ids match" do
|
|
2982
|
+
|
|
2983
|
+
before do
|
|
2984
|
+
person.posts_attributes =
|
|
2985
|
+
{
|
|
2986
|
+
"0" => { "id" => post_one.id, "title" => "First" },
|
|
2987
|
+
"1" => { "id" => post_two.id, "title" => "Second" }
|
|
2988
|
+
}
|
|
2989
|
+
end
|
|
2990
|
+
|
|
2991
|
+
context "when reloading the document" do
|
|
2992
|
+
|
|
2993
|
+
it "updates the first existing document" do
|
|
2994
|
+
expect(person.posts(true)[0].title).to eq("First")
|
|
2995
|
+
end
|
|
2996
|
+
|
|
2997
|
+
it "updates the second existing document" do
|
|
2998
|
+
expect(person.posts(true)[1].title).to eq("Second")
|
|
2999
|
+
end
|
|
3000
|
+
|
|
3001
|
+
it "does not add new documents" do
|
|
3002
|
+
expect(person.posts(true).size).to eq(2)
|
|
3003
|
+
end
|
|
3004
|
+
end
|
|
3005
|
+
|
|
3006
|
+
context "when there are no documents" do
|
|
3007
|
+
|
|
3008
|
+
before do
|
|
3009
|
+
person.posts.clear
|
|
3010
|
+
end
|
|
3011
|
+
|
|
3012
|
+
it "raises a document not found error" do
|
|
3013
|
+
expect {
|
|
3014
|
+
person.posts_attributes =
|
|
3015
|
+
{ "0" =>
|
|
3016
|
+
{ "id" => BSON::ObjectId.new.to_s, "title" => "Rogue" }
|
|
3017
|
+
}
|
|
3018
|
+
}.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Post with id\(s\)/)
|
|
3019
|
+
end
|
|
3020
|
+
end
|
|
3021
|
+
end
|
|
3022
|
+
|
|
3023
|
+
context "when the parent is freshly loaded from the db" do
|
|
3024
|
+
|
|
3025
|
+
before do
|
|
3026
|
+
person.reload
|
|
3027
|
+
end
|
|
3028
|
+
|
|
3029
|
+
context "when updating valid documents with invalid values" do
|
|
3030
|
+
|
|
3031
|
+
before do
|
|
3032
|
+
person.posts_attributes =
|
|
3033
|
+
{
|
|
3034
|
+
"0" => { "id" => post_one.id, "title" => "testing again" },
|
|
3035
|
+
"1" => { "id" => post_two.id, "title" => "$$$" }
|
|
3036
|
+
}
|
|
3037
|
+
person.save!
|
|
3038
|
+
end
|
|
3039
|
+
|
|
3040
|
+
it "does not perist the invalid value" do
|
|
3041
|
+
expect(post_two.reload.title).to eq("First response")
|
|
3042
|
+
end
|
|
3043
|
+
end
|
|
3044
|
+
end
|
|
3045
|
+
|
|
3046
|
+
context "when the ids do not match" do
|
|
3047
|
+
|
|
3048
|
+
it "raises an error" do
|
|
3049
|
+
expect {
|
|
3050
|
+
person.posts_attributes =
|
|
3051
|
+
{ "foo" => { "id" => "test", "title" => "Test" } }
|
|
3052
|
+
}.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Post with id\(s\)/)
|
|
3053
|
+
end
|
|
3054
|
+
end
|
|
3055
|
+
end
|
|
3056
|
+
|
|
3057
|
+
context "when destroy attributes are passed" do
|
|
3058
|
+
|
|
3059
|
+
context "when the ids match" do
|
|
3060
|
+
|
|
3061
|
+
context "when allow_destroy is true" do
|
|
3062
|
+
|
|
3063
|
+
before do
|
|
3064
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3065
|
+
Person.accepts_nested_attributes_for :posts, allow_destroy: true
|
|
3066
|
+
end
|
|
3067
|
+
|
|
3068
|
+
after do
|
|
3069
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3070
|
+
Person.accepts_nested_attributes_for :posts
|
|
3071
|
+
end
|
|
3072
|
+
|
|
3073
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3074
|
+
|
|
3075
|
+
context "when passed a #{truth} with destroy" do
|
|
3076
|
+
|
|
3077
|
+
before do
|
|
3078
|
+
person.posts_attributes =
|
|
3079
|
+
{
|
|
3080
|
+
"0" => { "id" => post_one.id, "_destroy" => truth },
|
|
3081
|
+
"1" => { "id" => post_two.id, "title" => "My Blog" }
|
|
3082
|
+
}
|
|
3083
|
+
end
|
|
3084
|
+
|
|
3085
|
+
context "when reloading the documents" do
|
|
3086
|
+
|
|
3087
|
+
it "deletes the marked document" do
|
|
3088
|
+
expect(person.posts(true).size).to eq(1)
|
|
3089
|
+
end
|
|
3090
|
+
|
|
3091
|
+
it "does not delete the unmarked document" do
|
|
3092
|
+
expect(person.posts(true).first.title).to eq("My Blog")
|
|
3093
|
+
end
|
|
3094
|
+
end
|
|
3095
|
+
end
|
|
3096
|
+
end
|
|
3097
|
+
|
|
3098
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3099
|
+
|
|
3100
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3101
|
+
|
|
3102
|
+
before do
|
|
3103
|
+
person.posts_attributes =
|
|
3104
|
+
{
|
|
3105
|
+
"0" => { "id" => post_one.id, "_destroy" => falsehood },
|
|
3106
|
+
"1" => { "id" => post_two.id, "title" => "My Blog" }
|
|
3107
|
+
}
|
|
3108
|
+
end
|
|
3109
|
+
|
|
3110
|
+
context "when reloading the document" do
|
|
3111
|
+
|
|
3112
|
+
it "does not delete the marked document" do
|
|
3113
|
+
expect(person.posts(true).size).to eq(2)
|
|
3114
|
+
end
|
|
3115
|
+
|
|
3116
|
+
it "does not delete the unmarked document" do
|
|
3117
|
+
expect(person.posts(true).map(&:title)).to include("My Blog")
|
|
3118
|
+
end
|
|
3119
|
+
end
|
|
3120
|
+
end
|
|
3121
|
+
end
|
|
3122
|
+
end
|
|
3123
|
+
|
|
3124
|
+
context "when allow_destroy is false" do
|
|
3125
|
+
|
|
3126
|
+
before do
|
|
3127
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3128
|
+
Person.accepts_nested_attributes_for :posts, allow_destroy: false
|
|
3129
|
+
end
|
|
3130
|
+
|
|
3131
|
+
after do
|
|
3132
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3133
|
+
Person.accepts_nested_attributes_for :posts
|
|
3134
|
+
end
|
|
3135
|
+
|
|
3136
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3137
|
+
|
|
3138
|
+
context "when passed a #{truth} with destroy" do
|
|
3139
|
+
|
|
3140
|
+
before do
|
|
3141
|
+
person.posts_attributes =
|
|
3142
|
+
{
|
|
3143
|
+
"0" => {
|
|
3144
|
+
"id" => post_one.id, "title" => "Another Title", "_destroy" => truth },
|
|
3145
|
+
"1" => { "id" => post_two.id, "title" => "New Title" }
|
|
3146
|
+
}
|
|
3147
|
+
end
|
|
3148
|
+
|
|
3149
|
+
context "when reloading the document" do
|
|
3150
|
+
|
|
3151
|
+
it "does not ignore the marked document" do
|
|
3152
|
+
expect(person.posts(true)[0].title).to eq("Another Title")
|
|
3153
|
+
end
|
|
3154
|
+
|
|
3155
|
+
it "does not delete the unmarked document" do
|
|
3156
|
+
expect(person.posts(true)[1].title).to eq("New Title")
|
|
3157
|
+
end
|
|
3158
|
+
|
|
3159
|
+
it "does not add additional documents" do
|
|
3160
|
+
expect(person.posts(true).size).to eq(2)
|
|
3161
|
+
end
|
|
3162
|
+
end
|
|
3163
|
+
end
|
|
3164
|
+
end
|
|
3165
|
+
|
|
3166
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3167
|
+
|
|
3168
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3169
|
+
|
|
3170
|
+
before do
|
|
3171
|
+
person.posts_attributes =
|
|
3172
|
+
{
|
|
3173
|
+
"0" => { "id" => post_one.id, "_destroy" => falsehood },
|
|
3174
|
+
"1" => { "id" => post_two.id, "title" => "New Title" }
|
|
3175
|
+
}
|
|
3176
|
+
end
|
|
3177
|
+
|
|
3178
|
+
context "when reloading the documents" do
|
|
3179
|
+
|
|
3180
|
+
it "does not delete the marked document" do
|
|
3181
|
+
expect(person.posts(true).size).to eq(2)
|
|
3182
|
+
end
|
|
3183
|
+
|
|
3184
|
+
it "does not delete the unmarked document" do
|
|
3185
|
+
expect(person.posts(true)[1].title).to eq("New Title")
|
|
3186
|
+
end
|
|
3187
|
+
end
|
|
3188
|
+
end
|
|
3189
|
+
end
|
|
3190
|
+
end
|
|
3191
|
+
|
|
3192
|
+
context "when allow_destroy is undefined" do
|
|
3193
|
+
|
|
3194
|
+
before do
|
|
3195
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3196
|
+
Person.accepts_nested_attributes_for :posts
|
|
3197
|
+
end
|
|
3198
|
+
|
|
3199
|
+
after do
|
|
3200
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3201
|
+
Person.accepts_nested_attributes_for :posts
|
|
3202
|
+
end
|
|
3203
|
+
|
|
3204
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3205
|
+
|
|
3206
|
+
context "when passed a #{truth} with destroy" do
|
|
3207
|
+
|
|
3208
|
+
before do
|
|
3209
|
+
person.posts_attributes =
|
|
3210
|
+
{
|
|
3211
|
+
"0" => {
|
|
3212
|
+
"id" => post_one.id,
|
|
3213
|
+
"title" => "Another Title",
|
|
3214
|
+
"_destroy" => truth
|
|
3215
|
+
},
|
|
3216
|
+
"1" => { "id" => post_two.id, "title" => "New Title" }
|
|
3217
|
+
}
|
|
3218
|
+
end
|
|
3219
|
+
|
|
3220
|
+
context "when reloading" do
|
|
3221
|
+
|
|
3222
|
+
it "does not ignore the marked document" do
|
|
3223
|
+
expect(person.posts(true).find(post_one.id).title).to eq("Another Title")
|
|
3224
|
+
end
|
|
3225
|
+
|
|
3226
|
+
it "does not delete the unmarked document" do
|
|
3227
|
+
expect(person.posts(true).find(post_two.id).title).to eq("New Title")
|
|
3228
|
+
end
|
|
3229
|
+
|
|
3230
|
+
it "does not add additional documents" do
|
|
3231
|
+
expect(person.posts(true).size).to eq(2)
|
|
3232
|
+
end
|
|
3233
|
+
end
|
|
3234
|
+
end
|
|
3235
|
+
end
|
|
3236
|
+
|
|
3237
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3238
|
+
|
|
3239
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3240
|
+
|
|
3241
|
+
before do
|
|
3242
|
+
person.posts_attributes =
|
|
3243
|
+
{
|
|
3244
|
+
"0" => { "id" => post_one.id, "_destroy" => falsehood },
|
|
3245
|
+
"1" => { "id" => post_two.id, "title" => "New Title" }
|
|
3246
|
+
}
|
|
3247
|
+
end
|
|
3248
|
+
|
|
3249
|
+
context "when reloading" do
|
|
3250
|
+
|
|
3251
|
+
it "does not delete the marked document" do
|
|
3252
|
+
expect(person.posts(true).size).to eq(2)
|
|
3253
|
+
end
|
|
3254
|
+
|
|
3255
|
+
it "does not delete the unmarked document" do
|
|
3256
|
+
expect(person.posts(true)[1].title).to eq("New Title")
|
|
3257
|
+
end
|
|
3258
|
+
end
|
|
3259
|
+
end
|
|
3260
|
+
end
|
|
3261
|
+
end
|
|
3262
|
+
end
|
|
3263
|
+
end
|
|
3264
|
+
end
|
|
3265
|
+
|
|
3266
|
+
context "when no ids are passed" do
|
|
3267
|
+
|
|
3268
|
+
context "when no destroy attributes are passed" do
|
|
3269
|
+
|
|
3270
|
+
context "when passing a hash of attributes" do
|
|
3271
|
+
|
|
3272
|
+
before do
|
|
3273
|
+
person.posts_attributes =
|
|
3274
|
+
{
|
|
3275
|
+
"4" => { "title" => "Third" },
|
|
3276
|
+
"1" => { "title" => "First" },
|
|
3277
|
+
"2" => { "title" => "Second" }
|
|
3278
|
+
}
|
|
3279
|
+
end
|
|
3280
|
+
|
|
3281
|
+
it "builds a new first document" do
|
|
3282
|
+
expect(person.posts[0].title).to eq("First")
|
|
3283
|
+
end
|
|
3284
|
+
|
|
3285
|
+
it "builds a new second document" do
|
|
3286
|
+
expect(person.posts[1].title).to eq("Second")
|
|
3287
|
+
end
|
|
3288
|
+
|
|
3289
|
+
it "builds a new third document" do
|
|
3290
|
+
expect(person.posts[2].title).to eq("Third")
|
|
3291
|
+
end
|
|
3292
|
+
|
|
3293
|
+
it "does not add extra documents" do
|
|
3294
|
+
expect(person.posts.size).to eq(3)
|
|
3295
|
+
end
|
|
3296
|
+
|
|
3297
|
+
it "does not persist the documents" do
|
|
3298
|
+
expect(person.posts.count).to eq(0)
|
|
3299
|
+
end
|
|
3300
|
+
|
|
3301
|
+
it "adds the documents in the sorted hash key order" do
|
|
3302
|
+
expect(person.posts.map(&:title)).to eq(
|
|
3303
|
+
[ "First", "Second", "Third" ]
|
|
3304
|
+
)
|
|
3305
|
+
end
|
|
3306
|
+
end
|
|
3307
|
+
|
|
3308
|
+
context "when passing an array of attributes" do
|
|
3309
|
+
|
|
3310
|
+
context "when the parent is saved" do
|
|
3311
|
+
|
|
3312
|
+
before do
|
|
3313
|
+
person.save!
|
|
3314
|
+
person.posts_attributes =
|
|
3315
|
+
[
|
|
3316
|
+
{ "title" => "Third" },
|
|
3317
|
+
{ "title" => "First" },
|
|
3318
|
+
{ "title" => "Second" }
|
|
3319
|
+
]
|
|
3320
|
+
end
|
|
3321
|
+
|
|
3322
|
+
it "builds a new first document" do
|
|
3323
|
+
expect(person.posts.first.title).to eq("Third")
|
|
3324
|
+
end
|
|
3325
|
+
|
|
3326
|
+
it "builds a new second document" do
|
|
3327
|
+
expect(person.posts.second.title).to eq("First")
|
|
3328
|
+
end
|
|
3329
|
+
|
|
3330
|
+
it "builds a new third document" do
|
|
3331
|
+
expect(person.posts.third.title).to eq("Second")
|
|
3332
|
+
end
|
|
3333
|
+
|
|
3334
|
+
it "does not add extra documents" do
|
|
3335
|
+
expect(person.posts.size).to eq(3)
|
|
3336
|
+
end
|
|
3337
|
+
|
|
3338
|
+
it "does not persist the documents" do
|
|
3339
|
+
expect(person.posts.count).to eq(0)
|
|
3340
|
+
end
|
|
3341
|
+
end
|
|
3342
|
+
end
|
|
3343
|
+
end
|
|
3344
|
+
|
|
3345
|
+
context "when a reject block is supplied" do
|
|
3346
|
+
|
|
3347
|
+
before do
|
|
3348
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3349
|
+
Person.accepts_nested_attributes_for \
|
|
3350
|
+
:posts, reject_if: ->(attrs){ attrs["title"].blank? }
|
|
3351
|
+
end
|
|
3352
|
+
|
|
3353
|
+
after do
|
|
3354
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3355
|
+
Person.accepts_nested_attributes_for :posts
|
|
3356
|
+
end
|
|
3357
|
+
|
|
3358
|
+
context "when the attributes match" do
|
|
3359
|
+
|
|
3360
|
+
before do
|
|
3361
|
+
person.posts_attributes =
|
|
3362
|
+
{ "3" => { "content" => "My first blog" } }
|
|
3363
|
+
end
|
|
3364
|
+
|
|
3365
|
+
it "does not add the new document" do
|
|
3366
|
+
expect(person.posts).to be_empty
|
|
3367
|
+
end
|
|
3368
|
+
end
|
|
3369
|
+
|
|
3370
|
+
context "when the attributes do not match" do
|
|
3371
|
+
|
|
3372
|
+
before do
|
|
3373
|
+
person.posts_attributes =
|
|
3374
|
+
{ "3" => { "title" => "Blogging" } }
|
|
3375
|
+
end
|
|
3376
|
+
|
|
3377
|
+
it "adds the new document" do
|
|
3378
|
+
expect(person.posts.size).to eq(1)
|
|
3379
|
+
end
|
|
3380
|
+
|
|
3381
|
+
it "sets the correct attributes" do
|
|
3382
|
+
expect(person.posts.first.title).to eq("Blogging")
|
|
3383
|
+
end
|
|
3384
|
+
end
|
|
3385
|
+
end
|
|
3386
|
+
|
|
3387
|
+
context "when :reject_if => :all_blank is supplied" do
|
|
3388
|
+
|
|
3389
|
+
before do
|
|
3390
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3391
|
+
Person.accepts_nested_attributes_for \
|
|
3392
|
+
:posts, reject_if: :all_blank
|
|
3393
|
+
end
|
|
3394
|
+
|
|
3395
|
+
after do
|
|
3396
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3397
|
+
Person.accepts_nested_attributes_for :posts
|
|
3398
|
+
end
|
|
3399
|
+
|
|
3400
|
+
context "when all attributes are blank" do
|
|
3401
|
+
|
|
3402
|
+
before do
|
|
3403
|
+
person.posts_attributes =
|
|
3404
|
+
{ "3" => { "content" => "" } }
|
|
3405
|
+
end
|
|
3406
|
+
|
|
3407
|
+
it "does not add the new document" do
|
|
3408
|
+
expect(person.posts).to be_empty
|
|
3409
|
+
end
|
|
3410
|
+
end
|
|
3411
|
+
|
|
3412
|
+
context "when an attribute is non-empty" do
|
|
3413
|
+
|
|
3414
|
+
before do
|
|
3415
|
+
person.posts_attributes =
|
|
3416
|
+
{ "3" => { "title" => "Blogging" } }
|
|
3417
|
+
end
|
|
3418
|
+
|
|
3419
|
+
it "adds the new document" do
|
|
3420
|
+
expect(person.posts.size).to eq(1)
|
|
3421
|
+
end
|
|
3422
|
+
|
|
3423
|
+
it "sets the correct attributes" do
|
|
3424
|
+
expect(person.posts.first.title).to eq("Blogging")
|
|
3425
|
+
end
|
|
3426
|
+
end
|
|
3427
|
+
end
|
|
3428
|
+
|
|
3429
|
+
context "when destroy attributes are passed" do
|
|
3430
|
+
|
|
3431
|
+
context "when allow_destroy is true" do
|
|
3432
|
+
|
|
3433
|
+
before do
|
|
3434
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3435
|
+
Person.accepts_nested_attributes_for :posts, allow_destroy: true
|
|
3436
|
+
end
|
|
3437
|
+
|
|
3438
|
+
after do
|
|
3439
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3440
|
+
Person.accepts_nested_attributes_for :posts
|
|
3441
|
+
end
|
|
3442
|
+
|
|
3443
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3444
|
+
|
|
3445
|
+
context "when passed a #{truth} with destroy" do
|
|
3446
|
+
|
|
3447
|
+
before do
|
|
3448
|
+
person.posts_attributes =
|
|
3449
|
+
{
|
|
3450
|
+
"0" => { "title" => "New Blog", "_destroy" => truth },
|
|
3451
|
+
"1" => { "title" => "Blog Two" }
|
|
3452
|
+
}
|
|
3453
|
+
end
|
|
3454
|
+
|
|
3455
|
+
it "ignores the marked document" do
|
|
3456
|
+
expect(person.posts.size).to eq(1)
|
|
3457
|
+
end
|
|
3458
|
+
|
|
3459
|
+
it "adds the new unmarked document" do
|
|
3460
|
+
expect(person.posts.first.title).to eq("Blog Two")
|
|
3461
|
+
end
|
|
3462
|
+
end
|
|
3463
|
+
end
|
|
3464
|
+
|
|
3465
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3466
|
+
|
|
3467
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3468
|
+
|
|
3469
|
+
before do
|
|
3470
|
+
person.posts_attributes =
|
|
3471
|
+
{
|
|
3472
|
+
"0" => { "title" => "New Blog", "_destroy" => falsehood },
|
|
3473
|
+
"1" => { "title" => "Blog Two" }
|
|
3474
|
+
}
|
|
3475
|
+
end
|
|
3476
|
+
|
|
3477
|
+
it "adds the new marked document" do
|
|
3478
|
+
expect(person.posts.first.title).to eq("New Blog")
|
|
3479
|
+
end
|
|
3480
|
+
|
|
3481
|
+
it "adds the new unmarked document" do
|
|
3482
|
+
expect(person.posts.last.title).to eq("Blog Two")
|
|
3483
|
+
end
|
|
3484
|
+
|
|
3485
|
+
it "does not add extra documents" do
|
|
3486
|
+
expect(person.posts.size).to eq(2)
|
|
3487
|
+
end
|
|
3488
|
+
end
|
|
3489
|
+
end
|
|
3490
|
+
end
|
|
3491
|
+
|
|
3492
|
+
context "when allow destroy is false" do
|
|
3493
|
+
|
|
3494
|
+
before do
|
|
3495
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3496
|
+
Person.accepts_nested_attributes_for :posts, allow_destroy: false
|
|
3497
|
+
end
|
|
3498
|
+
|
|
3499
|
+
after do
|
|
3500
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3501
|
+
Person.accepts_nested_attributes_for :posts
|
|
3502
|
+
end
|
|
3503
|
+
|
|
3504
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3505
|
+
|
|
3506
|
+
context "when passed a #{truth} with destroy" do
|
|
3507
|
+
|
|
3508
|
+
before do
|
|
3509
|
+
person.posts_attributes =
|
|
3510
|
+
{
|
|
3511
|
+
"0" => { "title" => "New Blog", "_destroy" => truth },
|
|
3512
|
+
"1" => { "title" => "Blog Two" }
|
|
3513
|
+
}
|
|
3514
|
+
end
|
|
3515
|
+
|
|
3516
|
+
it "adds the marked document" do
|
|
3517
|
+
expect(person.posts.first.title).to eq("New Blog")
|
|
3518
|
+
end
|
|
3519
|
+
|
|
3520
|
+
it "adds the new unmarked document" do
|
|
3521
|
+
expect(person.posts.last.title).to eq("Blog Two")
|
|
3522
|
+
end
|
|
3523
|
+
|
|
3524
|
+
it "adds the correct number of documents" do
|
|
3525
|
+
expect(person.posts.size).to eq(2)
|
|
3526
|
+
end
|
|
3527
|
+
end
|
|
3528
|
+
end
|
|
3529
|
+
|
|
3530
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3531
|
+
|
|
3532
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3533
|
+
|
|
3534
|
+
before do
|
|
3535
|
+
person.posts_attributes =
|
|
3536
|
+
{
|
|
3537
|
+
"0" => { "title" => "New Blog", "_destroy" => falsehood },
|
|
3538
|
+
"1" => { "title" => "Blog Two" }
|
|
3539
|
+
}
|
|
3540
|
+
end
|
|
3541
|
+
|
|
3542
|
+
it "adds the new marked document" do
|
|
3543
|
+
expect(person.posts.first.title).to eq("New Blog")
|
|
3544
|
+
end
|
|
3545
|
+
|
|
3546
|
+
it "adds the new unmarked document" do
|
|
3547
|
+
expect(person.posts.last.title).to eq("Blog Two")
|
|
3548
|
+
end
|
|
3549
|
+
|
|
3550
|
+
it "does not add extra documents" do
|
|
3551
|
+
expect(person.posts.size).to eq(2)
|
|
3552
|
+
end
|
|
3553
|
+
end
|
|
3554
|
+
end
|
|
3555
|
+
end
|
|
3556
|
+
|
|
3557
|
+
context "when allow destroy is not defined" do
|
|
3558
|
+
|
|
3559
|
+
before do
|
|
3560
|
+
Person.send(:undef_method, :posts_attributes=)
|
|
3561
|
+
Person.accepts_nested_attributes_for :posts
|
|
3562
|
+
end
|
|
3563
|
+
|
|
3564
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3565
|
+
|
|
3566
|
+
context "when passed a #{truth} with destroy" do
|
|
3567
|
+
|
|
3568
|
+
before do
|
|
3569
|
+
person.posts_attributes =
|
|
3570
|
+
{
|
|
3571
|
+
"0" => { "title" => "New Blog", "_destroy" => truth },
|
|
3572
|
+
"1" => { "title" => "Blog Two" }
|
|
3573
|
+
}
|
|
3574
|
+
end
|
|
3575
|
+
|
|
3576
|
+
it "adds the marked document" do
|
|
3577
|
+
expect(person.posts.first.title).to eq("New Blog")
|
|
3578
|
+
end
|
|
3579
|
+
|
|
3580
|
+
it "adds the new unmarked document" do
|
|
3581
|
+
expect(person.posts.last.title).to eq("Blog Two")
|
|
3582
|
+
end
|
|
3583
|
+
|
|
3584
|
+
it "adds the correct number of documents" do
|
|
3585
|
+
expect(person.posts.size).to eq(2)
|
|
3586
|
+
end
|
|
3587
|
+
end
|
|
3588
|
+
end
|
|
3589
|
+
|
|
3590
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3591
|
+
|
|
3592
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3593
|
+
|
|
3594
|
+
before do
|
|
3595
|
+
person.posts_attributes =
|
|
3596
|
+
{
|
|
3597
|
+
"0" => { "title" => "New Blog", "_destroy" => falsehood },
|
|
3598
|
+
"1" => { "title" => "Blog Two" }
|
|
3599
|
+
}
|
|
3600
|
+
end
|
|
3601
|
+
|
|
3602
|
+
it "adds the new marked document" do
|
|
3603
|
+
expect(person.posts.first.title).to eq("New Blog")
|
|
3604
|
+
end
|
|
3605
|
+
|
|
3606
|
+
it "adds the new unmarked document" do
|
|
3607
|
+
expect(person.posts.last.title).to eq("Blog Two")
|
|
3608
|
+
end
|
|
3609
|
+
|
|
3610
|
+
it "does not add extra documents" do
|
|
3611
|
+
expect(person.posts.size).to eq(2)
|
|
3612
|
+
end
|
|
3613
|
+
end
|
|
3614
|
+
end
|
|
3615
|
+
end
|
|
3616
|
+
end
|
|
3617
|
+
end
|
|
3618
|
+
|
|
3619
|
+
context "when the nested document is invalid" do
|
|
3620
|
+
|
|
3621
|
+
before do
|
|
3622
|
+
Person.validates_associated(:posts)
|
|
3623
|
+
end
|
|
3624
|
+
|
|
3625
|
+
after do
|
|
3626
|
+
Person.reset_callbacks(:validate)
|
|
3627
|
+
end
|
|
3628
|
+
|
|
3629
|
+
before do
|
|
3630
|
+
person.posts_attributes = {
|
|
3631
|
+
"0" => { title: "$$$" }
|
|
3632
|
+
}
|
|
3633
|
+
end
|
|
3634
|
+
|
|
3635
|
+
it "propagates invalidity to parent" do
|
|
3636
|
+
expect(person).to_not be_valid
|
|
3637
|
+
expect(person.posts.first).to_not be_valid
|
|
3638
|
+
end
|
|
3639
|
+
end
|
|
3640
|
+
|
|
3641
|
+
context "when a type is passed" do
|
|
3642
|
+
|
|
3643
|
+
let(:shipping_container) do
|
|
3644
|
+
ShippingContainer.new
|
|
3645
|
+
end
|
|
3646
|
+
|
|
3647
|
+
before do
|
|
3648
|
+
ShippingContainer.send(:undef_method, :vehicles_attributes=)
|
|
3649
|
+
ShippingContainer.accepts_nested_attributes_for :vehicles
|
|
3650
|
+
shipping_container.vehicles_attributes =
|
|
3651
|
+
{
|
|
3652
|
+
"foo" => { "_type" => "Car" },
|
|
3653
|
+
"bar" => { "_type" => "Truck" }
|
|
3654
|
+
}
|
|
3655
|
+
end
|
|
3656
|
+
|
|
3657
|
+
it "instantiates an object of the given type" do
|
|
3658
|
+
expect(shipping_container.vehicles.map(&:class)).to eq([Car, Truck])
|
|
3659
|
+
end
|
|
3660
|
+
end
|
|
3661
|
+
end
|
|
3662
|
+
|
|
3663
|
+
context "when the relation is a references many to many" do
|
|
3664
|
+
|
|
3665
|
+
let(:person) do
|
|
3666
|
+
Person.new
|
|
3667
|
+
end
|
|
3668
|
+
|
|
3669
|
+
let(:preference_one) do
|
|
3670
|
+
Preference.new(name: "First preference")
|
|
3671
|
+
end
|
|
3672
|
+
|
|
3673
|
+
let(:preference_two) do
|
|
3674
|
+
Preference.new(name: "First response")
|
|
3675
|
+
end
|
|
3676
|
+
|
|
3677
|
+
context "when a limit is specified" do
|
|
3678
|
+
|
|
3679
|
+
before do
|
|
3680
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
3681
|
+
Person.accepts_nested_attributes_for :preferences, limit: 2
|
|
3682
|
+
end
|
|
3683
|
+
|
|
3684
|
+
after do
|
|
3685
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
3686
|
+
Person.accepts_nested_attributes_for :preferences
|
|
3687
|
+
end
|
|
3688
|
+
|
|
3689
|
+
context "when more are provided than the limit" do
|
|
3690
|
+
|
|
3691
|
+
let(:attributes) do
|
|
3692
|
+
{
|
|
3693
|
+
"foo" => { "name" => "First" },
|
|
3694
|
+
"bar" => { "name" => "Second" },
|
|
3695
|
+
"baz" => { "name" => "Third" }
|
|
3696
|
+
}
|
|
3697
|
+
end
|
|
3698
|
+
|
|
3699
|
+
it "raises an error" do
|
|
3700
|
+
expect {
|
|
3701
|
+
person.preferences_attributes = attributes
|
|
3702
|
+
}.to raise_error(Mongoid::Errors::TooManyNestedAttributeRecords)
|
|
3703
|
+
end
|
|
3704
|
+
end
|
|
3705
|
+
|
|
3706
|
+
context "when less are provided than the limit" do
|
|
3707
|
+
|
|
3708
|
+
let(:attributes) do
|
|
3709
|
+
{
|
|
3710
|
+
"foo" => { "name" => "First" },
|
|
3711
|
+
"bar" => { "name" => "Second" }
|
|
3712
|
+
}
|
|
3713
|
+
end
|
|
3714
|
+
|
|
3715
|
+
before do
|
|
3716
|
+
person.preferences_attributes = attributes
|
|
3717
|
+
end
|
|
3718
|
+
|
|
3719
|
+
it "sets the documents on the relation" do
|
|
3720
|
+
expect(person.preferences.size).to eq(2)
|
|
3721
|
+
end
|
|
3722
|
+
end
|
|
3723
|
+
end
|
|
3724
|
+
|
|
3725
|
+
context "when ids are passed" do
|
|
3726
|
+
|
|
3727
|
+
let(:person) do
|
|
3728
|
+
Person.create!
|
|
3729
|
+
end
|
|
3730
|
+
|
|
3731
|
+
before do
|
|
3732
|
+
person.preferences << [ preference_one, preference_two ]
|
|
3733
|
+
end
|
|
3734
|
+
|
|
3735
|
+
context "when no destroy attributes are passed" do
|
|
3736
|
+
|
|
3737
|
+
context "when the ids match" do
|
|
3738
|
+
|
|
3739
|
+
before do
|
|
3740
|
+
person.preferences_attributes =
|
|
3741
|
+
{
|
|
3742
|
+
"0" => { "id" => preference_one.id, "name" => "First" },
|
|
3743
|
+
"1" => { "id" => preference_two.id, "name" => "Second" }
|
|
3744
|
+
}
|
|
3745
|
+
end
|
|
3746
|
+
|
|
3747
|
+
context "when reloading the document" do
|
|
3748
|
+
|
|
3749
|
+
it "updates the first existing document" do
|
|
3750
|
+
expect(person.preferences(true).first.name).to eq("First")
|
|
3751
|
+
end
|
|
3752
|
+
|
|
3753
|
+
it "updates the second existing document" do
|
|
3754
|
+
expect(person.preferences(true).second.name).to eq("Second")
|
|
3755
|
+
end
|
|
3756
|
+
|
|
3757
|
+
it "does not add new documents" do
|
|
3758
|
+
expect(person.preferences(true).size).to eq(2)
|
|
3759
|
+
end
|
|
3760
|
+
end
|
|
3761
|
+
end
|
|
3762
|
+
|
|
3763
|
+
context "when the ids do not match" do
|
|
3764
|
+
|
|
3765
|
+
it "raises an error" do
|
|
3766
|
+
expect {
|
|
3767
|
+
person.preferences_attributes =
|
|
3768
|
+
{ "foo" => { "id" => "test", "name" => "Test" } }
|
|
3769
|
+
}.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Preference with id\(s\)/)
|
|
3770
|
+
end
|
|
3771
|
+
end
|
|
3772
|
+
end
|
|
3773
|
+
|
|
3774
|
+
context "when destroy attributes are passed" do
|
|
3775
|
+
|
|
3776
|
+
context "when the ids match" do
|
|
3777
|
+
|
|
3778
|
+
context "when allow_destroy is true" do
|
|
3779
|
+
|
|
3780
|
+
before do
|
|
3781
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
3782
|
+
Person.accepts_nested_attributes_for :preferences, allow_destroy: true
|
|
3783
|
+
end
|
|
3784
|
+
|
|
3785
|
+
after do
|
|
3786
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
3787
|
+
Person.accepts_nested_attributes_for :preferences
|
|
3788
|
+
end
|
|
3789
|
+
|
|
3790
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3791
|
+
|
|
3792
|
+
context "when passed a #{truth} with destroy" do
|
|
3793
|
+
|
|
3794
|
+
before do
|
|
3795
|
+
person.preferences_attributes =
|
|
3796
|
+
{
|
|
3797
|
+
"0" => { "id" => preference_one.id, "_destroy" => truth },
|
|
3798
|
+
"1" => { "id" => preference_two.id, "name" => "My Blog" }
|
|
3799
|
+
}
|
|
3800
|
+
end
|
|
3801
|
+
|
|
3802
|
+
context "when reloading the documents" do
|
|
3803
|
+
|
|
3804
|
+
it "deletes the marked document" do
|
|
3805
|
+
expect(person.preferences(true).size).to eq(1)
|
|
3806
|
+
end
|
|
3807
|
+
|
|
3808
|
+
it "does not delete the unmarked document" do
|
|
3809
|
+
expect(person.preferences(true).first.name).to eq("My Blog")
|
|
3810
|
+
end
|
|
3811
|
+
end
|
|
3812
|
+
end
|
|
3813
|
+
end
|
|
3814
|
+
|
|
3815
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3816
|
+
|
|
3817
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3818
|
+
|
|
3819
|
+
before do
|
|
3820
|
+
person.preferences_attributes =
|
|
3821
|
+
{
|
|
3822
|
+
"0" => { "id" => preference_one.id, "_destroy" => falsehood },
|
|
3823
|
+
"1" => { "id" => preference_two.id, "name" => "My Blog" }
|
|
3824
|
+
}
|
|
3825
|
+
end
|
|
3826
|
+
|
|
3827
|
+
context "when reloading the document" do
|
|
3828
|
+
|
|
3829
|
+
it "does not delete the marked document" do
|
|
3830
|
+
expect(person.preferences(true).size).to eq(2)
|
|
3831
|
+
end
|
|
3832
|
+
|
|
3833
|
+
it "does not delete the unmarked document" do
|
|
3834
|
+
expect(person.preferences(true)[1].name).to eq("My Blog")
|
|
3835
|
+
end
|
|
3836
|
+
end
|
|
3837
|
+
end
|
|
3838
|
+
end
|
|
3839
|
+
end
|
|
3840
|
+
|
|
3841
|
+
context "when allow_destroy is false" do
|
|
3842
|
+
|
|
3843
|
+
before do
|
|
3844
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
3845
|
+
Person.accepts_nested_attributes_for :preferences, allow_destroy: false
|
|
3846
|
+
end
|
|
3847
|
+
|
|
3848
|
+
after do
|
|
3849
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
3850
|
+
Person.accepts_nested_attributes_for :preferences
|
|
3851
|
+
end
|
|
3852
|
+
|
|
3853
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3854
|
+
|
|
3855
|
+
context "when passed a #{truth} with destroy" do
|
|
3856
|
+
|
|
3857
|
+
before do
|
|
3858
|
+
person.preferences_attributes =
|
|
3859
|
+
{
|
|
3860
|
+
"0" => {
|
|
3861
|
+
"id" => preference_one.id, "name" => "Another Title", "_destroy" => truth },
|
|
3862
|
+
"1" => { "id" => preference_two.id, "name" => "New Title" }
|
|
3863
|
+
}
|
|
3864
|
+
end
|
|
3865
|
+
|
|
3866
|
+
context "when reloading the document" do
|
|
3867
|
+
|
|
3868
|
+
it "does not ignore the marked document" do
|
|
3869
|
+
expect(person.preferences(true)[0].name).to eq("Another Title")
|
|
3870
|
+
end
|
|
3871
|
+
|
|
3872
|
+
it "does not delete the unmarked document" do
|
|
3873
|
+
expect(person.preferences(true)[1].name).to eq("New Title")
|
|
3874
|
+
end
|
|
3875
|
+
|
|
3876
|
+
it "does not add additional documents" do
|
|
3877
|
+
expect(person.preferences(true).size).to eq(2)
|
|
3878
|
+
end
|
|
3879
|
+
end
|
|
3880
|
+
end
|
|
3881
|
+
end
|
|
3882
|
+
|
|
3883
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3884
|
+
|
|
3885
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3886
|
+
|
|
3887
|
+
before do
|
|
3888
|
+
person.preferences_attributes =
|
|
3889
|
+
{
|
|
3890
|
+
"0" => { "id" => preference_one.id, "_destroy" => falsehood },
|
|
3891
|
+
"1" => { "id" => preference_two.id, "name" => "New Title" }
|
|
3892
|
+
}
|
|
3893
|
+
end
|
|
3894
|
+
|
|
3895
|
+
context "when reloading the documents" do
|
|
3896
|
+
|
|
3897
|
+
it "does not delete the marked document" do
|
|
3898
|
+
expect(person.preferences(true).size).to eq(2)
|
|
3899
|
+
end
|
|
3900
|
+
|
|
3901
|
+
it "does not delete the unmarked document" do
|
|
3902
|
+
expect(person.preferences(true)[1].name).to eq("New Title")
|
|
3903
|
+
end
|
|
3904
|
+
end
|
|
3905
|
+
end
|
|
3906
|
+
end
|
|
3907
|
+
end
|
|
3908
|
+
|
|
3909
|
+
context "when allow_destroy is undefined" do
|
|
3910
|
+
|
|
3911
|
+
before do
|
|
3912
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
3913
|
+
Person.accepts_nested_attributes_for :preferences
|
|
3914
|
+
end
|
|
3915
|
+
|
|
3916
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
3917
|
+
|
|
3918
|
+
context "when passed a #{truth} with destroy" do
|
|
3919
|
+
|
|
3920
|
+
before do
|
|
3921
|
+
person.preferences_attributes =
|
|
3922
|
+
{
|
|
3923
|
+
"0" => {
|
|
3924
|
+
"id" => preference_one.id, "name" => "Another Title", "_destroy" => truth },
|
|
3925
|
+
"1" => { "id" => preference_two.id, "name" => "New Title" }
|
|
3926
|
+
}
|
|
3927
|
+
end
|
|
3928
|
+
|
|
3929
|
+
context "when reloading" do
|
|
3930
|
+
|
|
3931
|
+
it "does not ignore the marked document" do
|
|
3932
|
+
expect(person.preferences(true)[0].name).to eq("Another Title")
|
|
3933
|
+
end
|
|
3934
|
+
|
|
3935
|
+
it "does not delete the unmarked document" do
|
|
3936
|
+
expect(person.preferences(true)[1].name).to eq("New Title")
|
|
3937
|
+
end
|
|
3938
|
+
|
|
3939
|
+
it "does not add additional documents" do
|
|
3940
|
+
expect(person.preferences(true).size).to eq(2)
|
|
3941
|
+
end
|
|
3942
|
+
end
|
|
3943
|
+
end
|
|
3944
|
+
end
|
|
3945
|
+
|
|
3946
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
3947
|
+
|
|
3948
|
+
context "when passed a #{falsehood} with destroy" do
|
|
3949
|
+
|
|
3950
|
+
before do
|
|
3951
|
+
person.preferences_attributes =
|
|
3952
|
+
{
|
|
3953
|
+
"0" => { "id" => preference_one.id, "_destroy" => falsehood },
|
|
3954
|
+
"1" => { "id" => preference_two.id, "name" => "New Title" }
|
|
3955
|
+
}
|
|
3956
|
+
end
|
|
3957
|
+
|
|
3958
|
+
context "when reloading" do
|
|
3959
|
+
|
|
3960
|
+
it "does not delete the marked document" do
|
|
3961
|
+
expect(person.preferences(true).size).to eq(2)
|
|
3962
|
+
end
|
|
3963
|
+
|
|
3964
|
+
it "does not delete the unmarked document" do
|
|
3965
|
+
expect(person.preferences(true)[1].name).to eq("New Title")
|
|
3966
|
+
end
|
|
3967
|
+
end
|
|
3968
|
+
end
|
|
3969
|
+
end
|
|
3970
|
+
end
|
|
3971
|
+
end
|
|
3972
|
+
end
|
|
3973
|
+
end
|
|
3974
|
+
|
|
3975
|
+
context "when no ids are passed" do
|
|
3976
|
+
|
|
3977
|
+
context "when no destroy attributes are passed" do
|
|
3978
|
+
|
|
3979
|
+
before do
|
|
3980
|
+
person.preferences_attributes =
|
|
3981
|
+
{
|
|
3982
|
+
"4" => { "name" => "Third" },
|
|
3983
|
+
"1" => { "name" => "First" },
|
|
3984
|
+
"2" => { "name" => "Second" }
|
|
3985
|
+
}
|
|
3986
|
+
end
|
|
3987
|
+
|
|
3988
|
+
it "builds a new first document" do
|
|
3989
|
+
expect(person.preferences.first.name).to eq("First")
|
|
3990
|
+
end
|
|
3991
|
+
|
|
3992
|
+
it "builds a new second document" do
|
|
3993
|
+
expect(person.preferences.second.name).to eq("Second")
|
|
3994
|
+
end
|
|
3995
|
+
|
|
3996
|
+
it "builds a new third document" do
|
|
3997
|
+
expect(person.preferences.third.name).to eq("Third")
|
|
3998
|
+
end
|
|
3999
|
+
|
|
4000
|
+
it "does not add extra documents" do
|
|
4001
|
+
expect(person.preferences.size).to eq(3)
|
|
4002
|
+
end
|
|
4003
|
+
|
|
4004
|
+
it "adds the documents in the sorted hash key order" do
|
|
4005
|
+
expect(person.preferences.map(&:name)).to eq(
|
|
4006
|
+
[ "First", "Second", "Third" ]
|
|
4007
|
+
)
|
|
4008
|
+
end
|
|
4009
|
+
end
|
|
4010
|
+
|
|
4011
|
+
context "when a reject block is supplied" do
|
|
4012
|
+
|
|
4013
|
+
before do
|
|
4014
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4015
|
+
Person.accepts_nested_attributes_for \
|
|
4016
|
+
:preferences, reject_if: ->(attrs){ attrs["name"].blank? }
|
|
4017
|
+
end
|
|
4018
|
+
|
|
4019
|
+
after do
|
|
4020
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4021
|
+
Person.accepts_nested_attributes_for :preferences
|
|
4022
|
+
end
|
|
4023
|
+
|
|
4024
|
+
context "when the attributes match" do
|
|
4025
|
+
|
|
4026
|
+
before do
|
|
4027
|
+
person.preferences_attributes =
|
|
4028
|
+
{ "3" => { "content" => "My first blog" } }
|
|
4029
|
+
end
|
|
4030
|
+
|
|
4031
|
+
it "does not add the new document" do
|
|
4032
|
+
expect(person.preferences).to be_empty
|
|
4033
|
+
end
|
|
4034
|
+
end
|
|
4035
|
+
|
|
4036
|
+
context "when the attributes do not match" do
|
|
4037
|
+
|
|
4038
|
+
before do
|
|
4039
|
+
person.preferences_attributes =
|
|
4040
|
+
{ "3" => { "name" => "Blogging" } }
|
|
4041
|
+
end
|
|
4042
|
+
|
|
4043
|
+
it "adds the new document" do
|
|
4044
|
+
expect(person.preferences.size).to eq(1)
|
|
4045
|
+
end
|
|
4046
|
+
|
|
4047
|
+
it "sets the correct attributes" do
|
|
4048
|
+
expect(person.preferences.first.name).to eq("Blogging")
|
|
4049
|
+
end
|
|
4050
|
+
end
|
|
4051
|
+
end
|
|
4052
|
+
|
|
4053
|
+
context "when :reject_if => :all_blank is supplied" do
|
|
4054
|
+
|
|
4055
|
+
before do
|
|
4056
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4057
|
+
Person.accepts_nested_attributes_for \
|
|
4058
|
+
:preferences, reject_if: :all_blank
|
|
4059
|
+
end
|
|
4060
|
+
|
|
4061
|
+
after do
|
|
4062
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4063
|
+
Person.accepts_nested_attributes_for :preferences
|
|
4064
|
+
end
|
|
4065
|
+
|
|
4066
|
+
context "when all attributes are empty" do
|
|
4067
|
+
|
|
4068
|
+
before do
|
|
4069
|
+
person.preferences_attributes =
|
|
4070
|
+
{ "3" => { "content" => "" } }
|
|
4071
|
+
end
|
|
4072
|
+
|
|
4073
|
+
it "does not add the new document" do
|
|
4074
|
+
expect(person.preferences).to be_empty
|
|
4075
|
+
end
|
|
4076
|
+
end
|
|
4077
|
+
|
|
4078
|
+
context "when an attribute is non-empty" do
|
|
4079
|
+
|
|
4080
|
+
before do
|
|
4081
|
+
person.preferences_attributes =
|
|
4082
|
+
{ "3" => { "name" => "Blogging" } }
|
|
4083
|
+
end
|
|
4084
|
+
|
|
4085
|
+
it "adds the new document" do
|
|
4086
|
+
expect(person.preferences.size).to eq(1)
|
|
4087
|
+
end
|
|
4088
|
+
|
|
4089
|
+
it "sets the correct attributes" do
|
|
4090
|
+
expect(person.preferences.first.name).to eq("Blogging")
|
|
4091
|
+
end
|
|
4092
|
+
end
|
|
4093
|
+
end
|
|
4094
|
+
|
|
4095
|
+
context "when destroy attributes are passed" do
|
|
4096
|
+
|
|
4097
|
+
context "when allow_destroy is true" do
|
|
4098
|
+
|
|
4099
|
+
before do
|
|
4100
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4101
|
+
Person.accepts_nested_attributes_for :preferences, allow_destroy: true
|
|
4102
|
+
end
|
|
4103
|
+
|
|
4104
|
+
after do
|
|
4105
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4106
|
+
Person.accepts_nested_attributes_for :preferences
|
|
4107
|
+
end
|
|
4108
|
+
|
|
4109
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
4110
|
+
|
|
4111
|
+
context "when passed a #{truth} with destroy" do
|
|
4112
|
+
|
|
4113
|
+
before do
|
|
4114
|
+
person.preferences_attributes =
|
|
4115
|
+
{
|
|
4116
|
+
"0" => { "name" => "New Blog", "_destroy" => truth },
|
|
4117
|
+
"1" => { "name" => "Blog Two" }
|
|
4118
|
+
}
|
|
4119
|
+
end
|
|
4120
|
+
|
|
4121
|
+
it "ignores the marked document" do
|
|
4122
|
+
expect(person.preferences.size).to eq(1)
|
|
4123
|
+
end
|
|
4124
|
+
|
|
4125
|
+
it "adds the new unmarked document" do
|
|
4126
|
+
expect(person.preferences.first.name).to eq("Blog Two")
|
|
4127
|
+
end
|
|
4128
|
+
end
|
|
4129
|
+
end
|
|
4130
|
+
|
|
4131
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
4132
|
+
|
|
4133
|
+
context "when passed a #{falsehood} with destroy" do
|
|
4134
|
+
|
|
4135
|
+
before do
|
|
4136
|
+
person.preferences_attributes =
|
|
4137
|
+
{
|
|
4138
|
+
"0" => { "name" => "New Blog", "_destroy" => falsehood },
|
|
4139
|
+
"1" => { "name" => "Blog Two" }
|
|
4140
|
+
}
|
|
4141
|
+
end
|
|
4142
|
+
|
|
4143
|
+
it "adds the new marked document" do
|
|
4144
|
+
expect(person.preferences.first.name).to eq("New Blog")
|
|
4145
|
+
end
|
|
4146
|
+
|
|
4147
|
+
it "adds the new unmarked document" do
|
|
4148
|
+
expect(person.preferences.last.name).to eq("Blog Two")
|
|
4149
|
+
end
|
|
4150
|
+
|
|
4151
|
+
it "does not add extra documents" do
|
|
4152
|
+
expect(person.preferences.size).to eq(2)
|
|
4153
|
+
end
|
|
4154
|
+
end
|
|
4155
|
+
end
|
|
4156
|
+
end
|
|
4157
|
+
|
|
4158
|
+
context "when allow destroy is false" do
|
|
4159
|
+
|
|
4160
|
+
before do
|
|
4161
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4162
|
+
Person.accepts_nested_attributes_for :preferences, allow_destroy: false
|
|
4163
|
+
end
|
|
4164
|
+
|
|
4165
|
+
after do
|
|
4166
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4167
|
+
Person.accepts_nested_attributes_for :preferences
|
|
4168
|
+
end
|
|
4169
|
+
|
|
4170
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
4171
|
+
|
|
4172
|
+
context "when passed a #{truth} with destroy" do
|
|
4173
|
+
|
|
4174
|
+
before do
|
|
4175
|
+
person.preferences_attributes =
|
|
4176
|
+
{
|
|
4177
|
+
"0" => { "name" => "New Blog", "_destroy" => truth },
|
|
4178
|
+
"1" => { "name" => "Blog Two" }
|
|
4179
|
+
}
|
|
4180
|
+
end
|
|
4181
|
+
|
|
4182
|
+
it "adds the marked document" do
|
|
4183
|
+
expect(person.preferences.first.name).to eq("New Blog")
|
|
4184
|
+
end
|
|
4185
|
+
|
|
4186
|
+
it "adds the new unmarked document" do
|
|
4187
|
+
expect(person.preferences.last.name).to eq("Blog Two")
|
|
4188
|
+
end
|
|
4189
|
+
|
|
4190
|
+
it "adds the correct number of documents" do
|
|
4191
|
+
expect(person.preferences.size).to eq(2)
|
|
4192
|
+
end
|
|
4193
|
+
end
|
|
4194
|
+
end
|
|
4195
|
+
|
|
4196
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
4197
|
+
|
|
4198
|
+
context "when passed a #{falsehood} with destroy" do
|
|
4199
|
+
|
|
4200
|
+
before do
|
|
4201
|
+
person.preferences_attributes =
|
|
4202
|
+
{
|
|
4203
|
+
"0" => { "name" => "New Blog", "_destroy" => falsehood },
|
|
4204
|
+
"1" => { "name" => "Blog Two" }
|
|
4205
|
+
}
|
|
4206
|
+
end
|
|
4207
|
+
|
|
4208
|
+
it "adds the new marked document" do
|
|
4209
|
+
expect(person.preferences.first.name).to eq("New Blog")
|
|
4210
|
+
end
|
|
4211
|
+
|
|
4212
|
+
it "adds the new unmarked document" do
|
|
4213
|
+
expect(person.preferences.last.name).to eq("Blog Two")
|
|
4214
|
+
end
|
|
4215
|
+
|
|
4216
|
+
it "does not add extra documents" do
|
|
4217
|
+
expect(person.preferences.size).to eq(2)
|
|
4218
|
+
end
|
|
4219
|
+
end
|
|
4220
|
+
end
|
|
4221
|
+
end
|
|
4222
|
+
|
|
4223
|
+
context "when allow destroy is not defined" do
|
|
4224
|
+
|
|
4225
|
+
before do
|
|
4226
|
+
Person.send(:undef_method, :preferences_attributes=)
|
|
4227
|
+
Person.accepts_nested_attributes_for :preferences
|
|
4228
|
+
end
|
|
4229
|
+
|
|
4230
|
+
[ 1, "1", true, "true" ].each do |truth|
|
|
4231
|
+
|
|
4232
|
+
context "when passed a #{truth} with destroy" do
|
|
4233
|
+
|
|
4234
|
+
before do
|
|
4235
|
+
person.preferences_attributes =
|
|
4236
|
+
{
|
|
4237
|
+
"0" => { "name" => "New Blog", "_destroy" => truth },
|
|
4238
|
+
"1" => { "name" => "Blog Two" }
|
|
4239
|
+
}
|
|
4240
|
+
end
|
|
4241
|
+
|
|
4242
|
+
it "adds the marked document" do
|
|
4243
|
+
expect(person.preferences.first.name).to eq("New Blog")
|
|
4244
|
+
end
|
|
4245
|
+
|
|
4246
|
+
it "adds the new unmarked document" do
|
|
4247
|
+
expect(person.preferences.last.name).to eq("Blog Two")
|
|
4248
|
+
end
|
|
4249
|
+
|
|
4250
|
+
it "adds the correct number of documents" do
|
|
4251
|
+
expect(person.preferences.size).to eq(2)
|
|
4252
|
+
end
|
|
4253
|
+
end
|
|
4254
|
+
end
|
|
4255
|
+
|
|
4256
|
+
[ 0, "0", false, "false" ].each do |falsehood|
|
|
4257
|
+
|
|
4258
|
+
context "when passed a #{falsehood} with destroy" do
|
|
4259
|
+
|
|
4260
|
+
before do
|
|
4261
|
+
person.preferences_attributes =
|
|
4262
|
+
{
|
|
4263
|
+
"0" => { "name" => "New Blog", "_destroy" => falsehood },
|
|
4264
|
+
"1" => { "name" => "Blog Two" }
|
|
4265
|
+
}
|
|
4266
|
+
end
|
|
4267
|
+
|
|
4268
|
+
it "adds the new marked document" do
|
|
4269
|
+
expect(person.preferences.first.name).to eq("New Blog")
|
|
4270
|
+
end
|
|
4271
|
+
|
|
4272
|
+
it "adds the new unmarked document" do
|
|
4273
|
+
expect(person.preferences.last.name).to eq("Blog Two")
|
|
4274
|
+
end
|
|
4275
|
+
|
|
4276
|
+
it "does not add extra documents" do
|
|
4277
|
+
expect(person.preferences.size).to eq(2)
|
|
4278
|
+
end
|
|
4279
|
+
end
|
|
4280
|
+
end
|
|
4281
|
+
end
|
|
4282
|
+
end
|
|
4283
|
+
end
|
|
4284
|
+
|
|
4285
|
+
context "when the nested document is invalid" do
|
|
4286
|
+
|
|
4287
|
+
before do
|
|
4288
|
+
Person.validates_associated(:preferences)
|
|
4289
|
+
end
|
|
4290
|
+
|
|
4291
|
+
after do
|
|
4292
|
+
Person.reset_callbacks(:validate)
|
|
4293
|
+
end
|
|
4294
|
+
|
|
4295
|
+
before do
|
|
4296
|
+
person.preferences_attributes = {
|
|
4297
|
+
"0" => { name: 'x' }
|
|
4298
|
+
}
|
|
4299
|
+
end
|
|
4300
|
+
|
|
4301
|
+
it "propagates invalidity to parent" do
|
|
4302
|
+
expect(person.preferences.first).to_not be_valid
|
|
4303
|
+
expect(person).to_not be_valid
|
|
4304
|
+
end
|
|
4305
|
+
end
|
|
4306
|
+
end
|
|
4307
|
+
end
|
|
4308
|
+
end
|
|
4309
|
+
|
|
4310
|
+
describe "#update_attributes!" do
|
|
4311
|
+
|
|
4312
|
+
before do
|
|
4313
|
+
Person.send(:undef_method, :addresses_attributes=)
|
|
4314
|
+
Person.accepts_nested_attributes_for :addresses
|
|
4315
|
+
end
|
|
4316
|
+
|
|
4317
|
+
context "when embedding one level behind a has many" do
|
|
4318
|
+
|
|
4319
|
+
let(:node) do
|
|
4320
|
+
Node.create!
|
|
4321
|
+
end
|
|
4322
|
+
|
|
4323
|
+
let!(:server) do
|
|
4324
|
+
node.servers.create!(name: "prod")
|
|
4325
|
+
end
|
|
4326
|
+
|
|
4327
|
+
context "when adding a new embedded document" do
|
|
4328
|
+
|
|
4329
|
+
let(:attributes) do
|
|
4330
|
+
{ servers_attributes:
|
|
4331
|
+
{ "0" =>
|
|
4332
|
+
{
|
|
4333
|
+
_id: server.id,
|
|
4334
|
+
filesystems_attributes: {
|
|
4335
|
+
"0" => { name: "NFS" }
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
end
|
|
4341
|
+
|
|
4342
|
+
before do
|
|
4343
|
+
node.update_attributes!(attributes)
|
|
4344
|
+
end
|
|
4345
|
+
|
|
4346
|
+
it "adds the new embedded document" do
|
|
4347
|
+
expect(server.reload.filesystems.first.name).to eq("NFS")
|
|
4348
|
+
end
|
|
4349
|
+
|
|
4350
|
+
it "does not add more than one document" do
|
|
4351
|
+
expect(server.reload.filesystems.count).to eq(1)
|
|
4352
|
+
end
|
|
4353
|
+
end
|
|
4354
|
+
end
|
|
4355
|
+
|
|
4356
|
+
context "when deleting the child document" do
|
|
4357
|
+
|
|
4358
|
+
let(:person) do
|
|
4359
|
+
Person.create!
|
|
4360
|
+
end
|
|
4361
|
+
|
|
4362
|
+
let!(:service) do
|
|
4363
|
+
person.services.create!(sid: "123")
|
|
4364
|
+
end
|
|
4365
|
+
|
|
4366
|
+
let(:attributes) do
|
|
4367
|
+
{ services_attributes:
|
|
4368
|
+
{ "0" =>
|
|
4369
|
+
{ _id: service.id, sid: service.sid, _destroy: 1 }
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
end
|
|
4373
|
+
|
|
4374
|
+
before do
|
|
4375
|
+
person.update_attributes!(attributes)
|
|
4376
|
+
end
|
|
4377
|
+
|
|
4378
|
+
it "removes the document from the parent" do
|
|
4379
|
+
expect(person.services).to be_empty
|
|
4380
|
+
end
|
|
4381
|
+
|
|
4382
|
+
it "deletes the document" do
|
|
4383
|
+
expect(service).to be_destroyed
|
|
4384
|
+
end
|
|
4385
|
+
|
|
4386
|
+
it "runs the before destroy callbacks" do
|
|
4387
|
+
expect(service.before_destroy_called).to be true
|
|
4388
|
+
end
|
|
4389
|
+
|
|
4390
|
+
it "runs the after destroy callbacks" do
|
|
4391
|
+
expect(service.after_destroy_called).to be true
|
|
4392
|
+
end
|
|
4393
|
+
|
|
4394
|
+
it "clears the delayed atomic pulls from the parent" do
|
|
4395
|
+
expect(person.delayed_atomic_pulls).to be_empty
|
|
4396
|
+
end
|
|
4397
|
+
end
|
|
4398
|
+
|
|
4399
|
+
context "when nesting multiple levels and parent is timestamped" do
|
|
4400
|
+
|
|
4401
|
+
after do
|
|
4402
|
+
Address.reset_callbacks(:save)
|
|
4403
|
+
end
|
|
4404
|
+
|
|
4405
|
+
let(:dokument) do
|
|
4406
|
+
Dokument.create!
|
|
4407
|
+
end
|
|
4408
|
+
|
|
4409
|
+
let!(:address) do
|
|
4410
|
+
dokument.addresses.create!(street: "hobrecht")
|
|
4411
|
+
end
|
|
4412
|
+
|
|
4413
|
+
let!(:location) do
|
|
4414
|
+
address.locations.create!(name: "work")
|
|
4415
|
+
end
|
|
4416
|
+
|
|
4417
|
+
let(:attributes) do
|
|
4418
|
+
{
|
|
4419
|
+
locations_attributes: {
|
|
4420
|
+
a: { name: "home" }
|
|
4421
|
+
}
|
|
4422
|
+
}
|
|
4423
|
+
end
|
|
4424
|
+
|
|
4425
|
+
before do
|
|
4426
|
+
address.update_attributes!(attributes)
|
|
4427
|
+
address.reload
|
|
4428
|
+
end
|
|
4429
|
+
|
|
4430
|
+
it "does not add any extra locations" do
|
|
4431
|
+
expect(address.locations.size).to eq(2)
|
|
4432
|
+
end
|
|
4433
|
+
end
|
|
4434
|
+
|
|
4435
|
+
context "when nesting multiple levels" do
|
|
4436
|
+
|
|
4437
|
+
let!(:person) do
|
|
4438
|
+
Person.create!
|
|
4439
|
+
end
|
|
4440
|
+
|
|
4441
|
+
context "when second level is a one to many" do
|
|
4442
|
+
|
|
4443
|
+
let(:person_one) do
|
|
4444
|
+
Person.create!
|
|
4445
|
+
end
|
|
4446
|
+
|
|
4447
|
+
let!(:address_one) do
|
|
4448
|
+
person_one.addresses.create!(street: "hobrecht")
|
|
4449
|
+
end
|
|
4450
|
+
|
|
4451
|
+
let!(:location_one) do
|
|
4452
|
+
address_one.locations.create!(name: "home")
|
|
4453
|
+
end
|
|
4454
|
+
|
|
4455
|
+
context "when destroying a second level document" do
|
|
4456
|
+
|
|
4457
|
+
let(:attributes) do
|
|
4458
|
+
{ addresses_attributes:
|
|
4459
|
+
{ "0" =>
|
|
4460
|
+
{
|
|
4461
|
+
_id: address_one.id,
|
|
4462
|
+
locations_attributes: { "0" => { _id: location_one.id, _destroy: true }}
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4466
|
+
end
|
|
4467
|
+
|
|
4468
|
+
before do
|
|
4469
|
+
person_one.update_attributes!(attributes)
|
|
4470
|
+
end
|
|
4471
|
+
|
|
4472
|
+
it "deletes the document from the relation" do
|
|
4473
|
+
expect(address_one.locations).to be_empty
|
|
4474
|
+
end
|
|
4475
|
+
|
|
4476
|
+
it "persists the change" do
|
|
4477
|
+
expect(address_one.reload.locations).to be_empty
|
|
4478
|
+
end
|
|
4479
|
+
end
|
|
4480
|
+
|
|
4481
|
+
context "when destroying a second level document with callbacks" do
|
|
4482
|
+
|
|
4483
|
+
let(:band) do
|
|
4484
|
+
Band.create!(name: "Tool")
|
|
4485
|
+
end
|
|
4486
|
+
|
|
4487
|
+
let(:record) do
|
|
4488
|
+
band.records.create!(name: "Undertow")
|
|
4489
|
+
end
|
|
4490
|
+
|
|
4491
|
+
let!(:track) do
|
|
4492
|
+
record.tracks.create!(name: "Sober")
|
|
4493
|
+
end
|
|
4494
|
+
|
|
4495
|
+
context "when cascading callbacks" do
|
|
4496
|
+
|
|
4497
|
+
before do
|
|
4498
|
+
Band.accepts_nested_attributes_for :records
|
|
4499
|
+
Record.accepts_nested_attributes_for :tracks, allow_destroy: true
|
|
4500
|
+
end
|
|
4501
|
+
|
|
4502
|
+
after do
|
|
4503
|
+
Band.send(:undef_method, :records_attributes=)
|
|
4504
|
+
Record.send(:undef_method, :tracks_attributes=)
|
|
4505
|
+
end
|
|
4506
|
+
|
|
4507
|
+
let(:attributes) do
|
|
4508
|
+
{ records_attributes:
|
|
4509
|
+
{ "0" =>
|
|
4510
|
+
{
|
|
4511
|
+
_id: record.id,
|
|
4512
|
+
tracks_attributes: { "0" => { _id: track.id, _destroy: true }}
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
4515
|
+
}
|
|
4516
|
+
end
|
|
4517
|
+
|
|
4518
|
+
before do
|
|
4519
|
+
band.update_attributes!(attributes)
|
|
4520
|
+
end
|
|
4521
|
+
|
|
4522
|
+
it "removes the child from the relation" do
|
|
4523
|
+
expect(record.tracks).to be_empty
|
|
4524
|
+
end
|
|
4525
|
+
|
|
4526
|
+
it "deletes the child document" do
|
|
4527
|
+
expect(track).to be_destroyed
|
|
4528
|
+
end
|
|
4529
|
+
|
|
4530
|
+
it "runs the child's callbacks" do
|
|
4531
|
+
expect(track.before_destroy_called).to be true
|
|
4532
|
+
end
|
|
4533
|
+
end
|
|
4534
|
+
end
|
|
4535
|
+
|
|
4536
|
+
context "when adding new documents in both levels" do
|
|
4537
|
+
|
|
4538
|
+
context "when no documents has previously existed" do
|
|
4539
|
+
|
|
4540
|
+
let(:attributes) do
|
|
4541
|
+
{ addresses_attributes:
|
|
4542
|
+
{ "0" =>
|
|
4543
|
+
{
|
|
4544
|
+
street: "Alexanderstr",
|
|
4545
|
+
locations_attributes: { "0" => { name: "Home" } }
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
end
|
|
4550
|
+
|
|
4551
|
+
before do
|
|
4552
|
+
person.update_attributes!(attributes)
|
|
4553
|
+
end
|
|
4554
|
+
|
|
4555
|
+
let(:address) do
|
|
4556
|
+
person.addresses.first
|
|
4557
|
+
end
|
|
4558
|
+
|
|
4559
|
+
let(:location) do
|
|
4560
|
+
address.locations.first
|
|
4561
|
+
end
|
|
4562
|
+
|
|
4563
|
+
it "adds the new first level embedded document" do
|
|
4564
|
+
expect(address.street).to eq("Alexanderstr")
|
|
4565
|
+
end
|
|
4566
|
+
|
|
4567
|
+
it "adds the nested embedded document" do
|
|
4568
|
+
expect(location.name).to eq("Home")
|
|
4569
|
+
end
|
|
4570
|
+
end
|
|
4571
|
+
|
|
4572
|
+
context "when adding to an existing document in the first level" do
|
|
4573
|
+
|
|
4574
|
+
let!(:address) do
|
|
4575
|
+
person.addresses.create!(street: "hobrecht")
|
|
4576
|
+
end
|
|
4577
|
+
|
|
4578
|
+
let!(:location) do
|
|
4579
|
+
address.locations.create!(name: "work")
|
|
4580
|
+
end
|
|
4581
|
+
|
|
4582
|
+
let(:attributes) do
|
|
4583
|
+
{
|
|
4584
|
+
addresses_attributes: {
|
|
4585
|
+
a: { id: address.id, locations_attributes: { b: { name: "home" }}},
|
|
4586
|
+
c: { street: "pfluger" }
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
end
|
|
4590
|
+
|
|
4591
|
+
before do
|
|
4592
|
+
person.update_attributes!(attributes)
|
|
4593
|
+
person.reload
|
|
4594
|
+
end
|
|
4595
|
+
|
|
4596
|
+
it "adds the new location to the existing address" do
|
|
4597
|
+
expect(person.addresses.first.locations.count).to eq(2)
|
|
4598
|
+
end
|
|
4599
|
+
|
|
4600
|
+
it "adds the new address" do
|
|
4601
|
+
expect(person.addresses.count).to eq(2)
|
|
4602
|
+
end
|
|
4603
|
+
end
|
|
4604
|
+
end
|
|
4605
|
+
end
|
|
4606
|
+
|
|
4607
|
+
context "when the second level is a one to one" do
|
|
4608
|
+
|
|
4609
|
+
context "when the nested document is new" do
|
|
4610
|
+
|
|
4611
|
+
let(:attributes) do
|
|
4612
|
+
{ addresses_attributes:
|
|
4613
|
+
{ "0" =>
|
|
4614
|
+
{
|
|
4615
|
+
street: "Alexanderstr",
|
|
4616
|
+
code_attributes: { name: "Home" }
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
end
|
|
4621
|
+
|
|
4622
|
+
before do
|
|
4623
|
+
person.update_attributes!(attributes)
|
|
4624
|
+
end
|
|
4625
|
+
|
|
4626
|
+
let(:address) do
|
|
4627
|
+
person.addresses.first
|
|
4628
|
+
end
|
|
4629
|
+
|
|
4630
|
+
let(:code) do
|
|
4631
|
+
address.code
|
|
4632
|
+
end
|
|
4633
|
+
|
|
4634
|
+
it "adds the new first level embedded document" do
|
|
4635
|
+
expect(address.street).to eq("Alexanderstr")
|
|
4636
|
+
end
|
|
4637
|
+
|
|
4638
|
+
it "adds the nested embedded document" do
|
|
4639
|
+
expect(code.name).to eq("Home")
|
|
4640
|
+
end
|
|
4641
|
+
end
|
|
4642
|
+
end
|
|
4643
|
+
|
|
4644
|
+
context "when the nested document is getting updated" do
|
|
4645
|
+
|
|
4646
|
+
context "when the nested document is not polymorphic" do
|
|
4647
|
+
|
|
4648
|
+
let!(:address) do
|
|
4649
|
+
person.addresses.create!(street: "Alexanderstr", number: 1)
|
|
4650
|
+
end
|
|
4651
|
+
|
|
4652
|
+
let!(:code) do
|
|
4653
|
+
address.create_code(name: "Home")
|
|
4654
|
+
end
|
|
4655
|
+
|
|
4656
|
+
let(:attributes) do
|
|
4657
|
+
{ addresses_attributes:
|
|
4658
|
+
{ "0" =>
|
|
4659
|
+
{
|
|
4660
|
+
_id: address.id,
|
|
4661
|
+
number: 45,
|
|
4662
|
+
code_attributes: {
|
|
4663
|
+
_id: code.id,
|
|
4664
|
+
name: "Work"
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
}
|
|
4669
|
+
end
|
|
4670
|
+
|
|
4671
|
+
before do
|
|
4672
|
+
person.update_attributes!(attributes)
|
|
4673
|
+
end
|
|
4674
|
+
|
|
4675
|
+
it "updates the first level embedded document" do
|
|
4676
|
+
expect(address.number).to eq(45)
|
|
4677
|
+
end
|
|
4678
|
+
|
|
4679
|
+
it "updates the nested embedded document" do
|
|
4680
|
+
expect(code.name).to eq("Work")
|
|
4681
|
+
end
|
|
4682
|
+
end
|
|
4683
|
+
|
|
4684
|
+
context "when the nested document is polymorphic" do
|
|
4685
|
+
|
|
4686
|
+
context "when the first level is an embeds many" do
|
|
4687
|
+
|
|
4688
|
+
let!(:address) do
|
|
4689
|
+
person.addresses.create!(street: "Alexanderstr", number: 1)
|
|
4690
|
+
end
|
|
4691
|
+
|
|
4692
|
+
let!(:target) do
|
|
4693
|
+
address.create_target(name: "test")
|
|
4694
|
+
end
|
|
4695
|
+
|
|
4696
|
+
let(:attributes) do
|
|
4697
|
+
{ addresses_attributes:
|
|
4698
|
+
{ "0" =>
|
|
4699
|
+
{
|
|
4700
|
+
_id: address.id,
|
|
4701
|
+
number: 45,
|
|
4702
|
+
target_attributes: {
|
|
4703
|
+
_id: target.id,
|
|
4704
|
+
name: "updated"
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4709
|
+
end
|
|
4710
|
+
|
|
4711
|
+
before do
|
|
4712
|
+
person.update_attributes!(attributes)
|
|
4713
|
+
end
|
|
4714
|
+
|
|
4715
|
+
it "updates the first level embedded document" do
|
|
4716
|
+
expect(address.number).to eq(45)
|
|
4717
|
+
end
|
|
4718
|
+
|
|
4719
|
+
it "updates the nested embedded document" do
|
|
4720
|
+
expect(target.name).to eq("updated")
|
|
4721
|
+
end
|
|
4722
|
+
end
|
|
4723
|
+
|
|
4724
|
+
context "when the first level is an embeds one" do
|
|
4725
|
+
|
|
4726
|
+
context "when the id is passed as a string" do
|
|
4727
|
+
|
|
4728
|
+
let!(:name) do
|
|
4729
|
+
person.create_name(first_name: "john", last_name: "doe")
|
|
4730
|
+
end
|
|
4731
|
+
|
|
4732
|
+
let!(:language) do
|
|
4733
|
+
name.create_language(name: "english")
|
|
4734
|
+
end
|
|
4735
|
+
|
|
4736
|
+
let(:attributes) do
|
|
4737
|
+
{ name_attributes:
|
|
4738
|
+
{
|
|
4739
|
+
language_attributes: {
|
|
4740
|
+
_id: language.id.to_s,
|
|
4741
|
+
name: "deutsch"
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
}
|
|
4745
|
+
end
|
|
4746
|
+
|
|
4747
|
+
before do
|
|
4748
|
+
person.update_attributes!(attributes)
|
|
4749
|
+
end
|
|
4750
|
+
|
|
4751
|
+
it "updates the nested embedded document" do
|
|
4752
|
+
expect(language.name).to eq("deutsch")
|
|
4753
|
+
end
|
|
4754
|
+
end
|
|
4755
|
+
end
|
|
4756
|
+
end
|
|
4757
|
+
end
|
|
4758
|
+
end
|
|
4759
|
+
|
|
4760
|
+
context "when the relation is a has many" do
|
|
4761
|
+
|
|
4762
|
+
context "when updating with valid attributes" do
|
|
4763
|
+
|
|
4764
|
+
let(:user) do
|
|
4765
|
+
User.create!
|
|
4766
|
+
end
|
|
4767
|
+
|
|
4768
|
+
let(:params) do
|
|
4769
|
+
{ posts_attributes:
|
|
4770
|
+
{ "0" => { title: "Testing" }}
|
|
4771
|
+
}
|
|
4772
|
+
end
|
|
4773
|
+
|
|
4774
|
+
before do
|
|
4775
|
+
user.update_attributes!(params)
|
|
4776
|
+
end
|
|
4777
|
+
|
|
4778
|
+
around do |example|
|
|
4779
|
+
original_relations = User.relations
|
|
4780
|
+
User.has_many :posts, foreign_key: :author_id, validate: false, autosave: true
|
|
4781
|
+
example.run
|
|
4782
|
+
user.relations = original_relations
|
|
4783
|
+
end
|
|
4784
|
+
|
|
4785
|
+
let(:post) do
|
|
4786
|
+
user.posts.first
|
|
4787
|
+
end
|
|
4788
|
+
|
|
4789
|
+
it "adds the new document to the relation" do
|
|
4790
|
+
expect(post.title).to eq("Testing")
|
|
4791
|
+
end
|
|
4792
|
+
|
|
4793
|
+
it "autosaves the relation" do
|
|
4794
|
+
expect(user.posts(true).first.title).to eq("Testing")
|
|
4795
|
+
end
|
|
4796
|
+
end
|
|
4797
|
+
|
|
4798
|
+
context "when the document is freshly loaded from the db" do
|
|
4799
|
+
|
|
4800
|
+
let!(:node) do
|
|
4801
|
+
Node.create!
|
|
4802
|
+
end
|
|
4803
|
+
|
|
4804
|
+
let!(:server) do
|
|
4805
|
+
node.servers.create!(name: "test")
|
|
4806
|
+
end
|
|
4807
|
+
|
|
4808
|
+
before do
|
|
4809
|
+
node.reload
|
|
4810
|
+
end
|
|
4811
|
+
|
|
4812
|
+
context "when updating invalid attributes" do
|
|
4813
|
+
|
|
4814
|
+
let!(:update) do
|
|
4815
|
+
node.update_attributes({
|
|
4816
|
+
servers_attributes: { "0" => { "_id" => server.id, "name" => "" }}
|
|
4817
|
+
})
|
|
4818
|
+
end
|
|
4819
|
+
|
|
4820
|
+
it "returns false" do
|
|
4821
|
+
expect(update).to be false
|
|
4822
|
+
end
|
|
4823
|
+
|
|
4824
|
+
it "does not update the child document" do
|
|
4825
|
+
expect(server.reload.name).to eq("test")
|
|
4826
|
+
end
|
|
4827
|
+
|
|
4828
|
+
it "adds the errors to the document" do
|
|
4829
|
+
expect(node.errors[:servers]).to_not be_nil
|
|
4830
|
+
end
|
|
4831
|
+
end
|
|
4832
|
+
end
|
|
4833
|
+
end
|
|
4834
|
+
|
|
4835
|
+
context "when the relation is an embeds many" do
|
|
4836
|
+
|
|
4837
|
+
let(:league) do
|
|
4838
|
+
League.create!
|
|
4839
|
+
end
|
|
4840
|
+
|
|
4841
|
+
let!(:division) do
|
|
4842
|
+
league.divisions.create!(name: "Old Name")
|
|
4843
|
+
end
|
|
4844
|
+
|
|
4845
|
+
context "when additional validation is set" do
|
|
4846
|
+
|
|
4847
|
+
before do
|
|
4848
|
+
League.validates_presence_of(:divisions)
|
|
4849
|
+
end
|
|
4850
|
+
|
|
4851
|
+
after do
|
|
4852
|
+
League.reset_callbacks(:validate)
|
|
4853
|
+
end
|
|
4854
|
+
|
|
4855
|
+
context "when validation fails" do
|
|
4856
|
+
|
|
4857
|
+
let(:division) do
|
|
4858
|
+
Division.new
|
|
4859
|
+
end
|
|
4860
|
+
|
|
4861
|
+
let(:league) do
|
|
4862
|
+
League.create!(divisions: [division])
|
|
4863
|
+
end
|
|
4864
|
+
|
|
4865
|
+
let(:error_raising_update) do
|
|
4866
|
+
league.update!(:divisions => nil)
|
|
4867
|
+
end
|
|
4868
|
+
|
|
4869
|
+
before do
|
|
4870
|
+
league.update(:divisions => nil)
|
|
4871
|
+
league.reload
|
|
4872
|
+
end
|
|
4873
|
+
|
|
4874
|
+
it "the update raises an error" do
|
|
4875
|
+
expect{ error_raising_update }.to raise_error(Mongoid::Errors::Validations)
|
|
4876
|
+
end
|
|
4877
|
+
|
|
4878
|
+
it "the update does not occur" do
|
|
4879
|
+
expect(league.divisions.first).to eq(division)
|
|
4880
|
+
end
|
|
4881
|
+
|
|
4882
|
+
it "the document is inaccurately marked destroyed (you fixed the bug if you broke this!)" do
|
|
4883
|
+
expect(division).to be_destroyed
|
|
4884
|
+
end
|
|
4885
|
+
end
|
|
4886
|
+
end
|
|
4887
|
+
|
|
4888
|
+
context "when no additional validation is set" do
|
|
4889
|
+
|
|
4890
|
+
let(:params) do
|
|
4891
|
+
{ divisions_attributes:
|
|
4892
|
+
{ "0" => { id: division.id.to_s, name: "New Name" }}
|
|
4893
|
+
}
|
|
4894
|
+
end
|
|
4895
|
+
|
|
4896
|
+
before do
|
|
4897
|
+
league.update_attributes!(params)
|
|
4898
|
+
end
|
|
4899
|
+
|
|
4900
|
+
it "sets the nested attributes" do
|
|
4901
|
+
expect(league.reload.divisions.first.name).to eq("New Name")
|
|
4902
|
+
end
|
|
4903
|
+
|
|
4904
|
+
context "with corrupted data" do
|
|
4905
|
+
|
|
4906
|
+
before do
|
|
4907
|
+
league[:league] = params
|
|
4908
|
+
end
|
|
4909
|
+
|
|
4910
|
+
let(:new_params) do
|
|
4911
|
+
{ divisions_attributes:
|
|
4912
|
+
{ "0" => { id: division.id.to_s, name: "Name" }}
|
|
4913
|
+
}
|
|
4914
|
+
end
|
|
4915
|
+
|
|
4916
|
+
before do
|
|
4917
|
+
league.update_attributes!(new_params)
|
|
4918
|
+
end
|
|
4919
|
+
|
|
4920
|
+
it "sets the nested attributes" do
|
|
4921
|
+
expect(league.reload.divisions.first.name).to eq("Name")
|
|
4922
|
+
end
|
|
4923
|
+
end
|
|
4924
|
+
end
|
|
4925
|
+
end
|
|
4926
|
+
end
|
|
4927
|
+
|
|
4928
|
+
context "when destroying has_many child using nested attributes" do
|
|
4929
|
+
let(:school) do
|
|
4930
|
+
School.create
|
|
4931
|
+
end
|
|
4932
|
+
|
|
4933
|
+
let!(:student) do
|
|
4934
|
+
school.students.create
|
|
4935
|
+
end
|
|
4936
|
+
|
|
4937
|
+
before do
|
|
4938
|
+
school.attributes = {
|
|
4939
|
+
'_id': school.id,
|
|
4940
|
+
'students_attributes': [{
|
|
4941
|
+
'_id': student.id,
|
|
4942
|
+
'_destroy': 1
|
|
4943
|
+
}]
|
|
4944
|
+
}
|
|
4945
|
+
end
|
|
4946
|
+
|
|
4947
|
+
it "is able to access the parent in the after_destroy callback" do
|
|
4948
|
+
expect(school.after_destroy_triggered).to eq(true)
|
|
4949
|
+
end
|
|
4950
|
+
end
|
|
4951
|
+
|
|
4952
|
+
context "when destroying has_many child using nested attributes" do
|
|
4953
|
+
let(:school) do
|
|
4954
|
+
HabtmmSchool.create!(students: [student])
|
|
4955
|
+
end
|
|
4956
|
+
|
|
4957
|
+
let(:student) do
|
|
4958
|
+
HabtmmStudent.create!
|
|
4959
|
+
end
|
|
4960
|
+
|
|
4961
|
+
before do
|
|
4962
|
+
student.schools << school
|
|
4963
|
+
school.attributes = {
|
|
4964
|
+
'_id': school.id,
|
|
4965
|
+
'students_attributes': [{
|
|
4966
|
+
'_id': student.id,
|
|
4967
|
+
'_destroy': 1
|
|
4968
|
+
}]
|
|
4969
|
+
}
|
|
4970
|
+
end
|
|
4971
|
+
|
|
4972
|
+
it "is able to access the parent in the after_destroy callback" do
|
|
4973
|
+
expect(school.reload.after_destroy_triggered).to eq(true)
|
|
4974
|
+
end
|
|
4975
|
+
end
|
|
4976
|
+
|
|
4977
|
+
context "when using a multi-leveled nested attribute on a referenced association" do
|
|
4978
|
+
let(:author) { NestedAuthor.create }
|
|
4979
|
+
let(:one_level_params) { { post_attributes: { title: 'test' } } }
|
|
4980
|
+
let(:two_levels_params) { { post_attributes: { comments_attributes: [ { body: 'test' } ] } } }
|
|
4981
|
+
|
|
4982
|
+
it "creates a 1st-depth child model" do
|
|
4983
|
+
author.update_attributes(one_level_params)
|
|
4984
|
+
expect(author.post.persisted?).to be true
|
|
4985
|
+
end
|
|
4986
|
+
|
|
4987
|
+
it "creates a 1st-depth child model, and a 2nd-depth child model" do
|
|
4988
|
+
author.update_attributes(two_levels_params)
|
|
4989
|
+
expect(author.post.comments.count).to eq 1
|
|
4990
|
+
end
|
|
4991
|
+
|
|
4992
|
+
context "the 1st-depth child model already exists" do
|
|
4993
|
+
it "creates a 2nd-depth child model" do
|
|
4994
|
+
author.create_post(title: 'test')
|
|
4995
|
+
author.update_attributes(two_levels_params)
|
|
4996
|
+
expect(author.post.comments.count).to eq 1
|
|
4997
|
+
end
|
|
4998
|
+
end
|
|
4999
|
+
end
|
|
5000
|
+
end
|