activerecord 2.3.18 → 3.2.22
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1014 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +222 -0
- data/examples/performance.rb +100 -126
- data/examples/simple.rb +14 -0
- data/lib/active_record/aggregations.rb +93 -99
- data/lib/active_record/associations/alias_tracker.rb +76 -0
- data/lib/active_record/associations/association.rb +247 -0
- data/lib/active_record/associations/association_scope.rb +134 -0
- data/lib/active_record/associations/belongs_to_association.rb +54 -61
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +17 -59
- data/lib/active_record/associations/builder/association.rb +55 -0
- data/lib/active_record/associations/builder/belongs_to.rb +88 -0
- data/lib/active_record/associations/builder/collection_association.rb +75 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
- data/lib/active_record/associations/builder/has_many.rb +71 -0
- data/lib/active_record/associations/builder/has_one.rb +62 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +580 -0
- data/lib/active_record/associations/collection_proxy.rb +133 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +39 -119
- data/lib/active_record/associations/has_many_association.rb +60 -79
- data/lib/active_record/associations/has_many_through_association.rb +127 -206
- data/lib/active_record/associations/has_one_association.rb +55 -114
- data/lib/active_record/associations/has_one_through_association.rb +25 -26
- data/lib/active_record/associations/join_dependency/join_association.rb +159 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_dependency.rb +214 -0
- data/lib/active_record/associations/join_helper.rb +55 -0
- data/lib/active_record/associations/preloader/association.rb +125 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +67 -0
- data/lib/active_record/associations/preloader.rb +181 -0
- data/lib/active_record/associations/singular_association.rb +64 -0
- data/lib/active_record/associations/through_association.rb +87 -0
- data/lib/active_record/associations.rb +693 -1337
- data/lib/active_record/attribute_assignment.rb +221 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
- data/lib/active_record/attribute_methods/dirty.rb +111 -0
- data/lib/active_record/attribute_methods/primary_key.rb +114 -0
- data/lib/active_record/attribute_methods/query.rb +39 -0
- data/lib/active_record/attribute_methods/read.rb +136 -0
- data/lib/active_record/attribute_methods/serialization.rb +120 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
- data/lib/active_record/attribute_methods/write.rb +70 -0
- data/lib/active_record/attribute_methods.rb +211 -339
- data/lib/active_record/autosave_association.rb +179 -149
- data/lib/active_record/base.rb +401 -2907
- data/lib/active_record/callbacks.rb +91 -176
- data/lib/active_record/coders/yaml_column.rb +41 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +236 -119
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +110 -58
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +71 -21
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +81 -311
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +194 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +130 -83
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
- data/lib/active_record/connection_adapters/column.rb +296 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +280 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +272 -493
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +650 -405
- data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +30 -9
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +276 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/counter_cache.rb +123 -0
- data/lib/active_record/dynamic_finder_match.rb +41 -14
- data/lib/active_record/dynamic_matchers.rb +84 -0
- data/lib/active_record/dynamic_scope_match.rb +13 -15
- data/lib/active_record/errors.rb +195 -0
- data/lib/active_record/explain.rb +86 -0
- data/lib/active_record/explain_subscriber.rb +25 -0
- data/lib/active_record/fixtures/file.rb +65 -0
- data/lib/active_record/fixtures.rb +695 -770
- data/lib/active_record/identity_map.rb +162 -0
- data/lib/active_record/inheritance.rb +174 -0
- data/lib/active_record/integration.rb +60 -0
- data/lib/active_record/locale/en.yml +9 -27
- data/lib/active_record/locking/optimistic.rb +76 -73
- data/lib/active_record/locking/pessimistic.rb +32 -10
- data/lib/active_record/log_subscriber.rb +72 -0
- data/lib/active_record/migration/command_recorder.rb +105 -0
- data/lib/active_record/migration.rb +415 -205
- data/lib/active_record/model_schema.rb +368 -0
- data/lib/active_record/nested_attributes.rb +153 -63
- data/lib/active_record/observer.rb +27 -103
- data/lib/active_record/persistence.rb +376 -0
- data/lib/active_record/query_cache.rb +49 -8
- data/lib/active_record/querying.rb +58 -0
- data/lib/active_record/railtie.rb +131 -0
- data/lib/active_record/railties/console_sandbox.rb +6 -0
- data/lib/active_record/railties/controller_runtime.rb +49 -0
- data/lib/active_record/railties/databases.rake +659 -0
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +26 -0
- data/lib/active_record/reflection.rb +269 -120
- data/lib/active_record/relation/batches.rb +90 -0
- data/lib/active_record/relation/calculations.rb +372 -0
- data/lib/active_record/relation/delegation.rb +49 -0
- data/lib/active_record/relation/finder_methods.rb +402 -0
- data/lib/active_record/relation/predicate_builder.rb +63 -0
- data/lib/active_record/relation/query_methods.rb +417 -0
- data/lib/active_record/relation/spawn_methods.rb +180 -0
- data/lib/active_record/relation.rb +537 -0
- data/lib/active_record/result.rb +40 -0
- data/lib/active_record/sanitization.rb +194 -0
- data/lib/active_record/schema.rb +9 -6
- data/lib/active_record/schema_dumper.rb +55 -32
- data/lib/active_record/scoping/default.rb +142 -0
- data/lib/active_record/scoping/named.rb +200 -0
- data/lib/active_record/scoping.rb +152 -0
- data/lib/active_record/serialization.rb +8 -91
- data/lib/active_record/serializers/xml_serializer.rb +43 -197
- data/lib/active_record/session_store.rb +129 -103
- data/lib/active_record/store.rb +52 -0
- data/lib/active_record/test_case.rb +30 -23
- data/lib/active_record/timestamp.rb +95 -52
- data/lib/active_record/transactions.rb +212 -66
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +43 -0
- data/lib/active_record/validations/uniqueness.rb +180 -0
- data/lib/active_record/validations.rb +43 -1106
- data/lib/active_record/version.rb +5 -4
- data/lib/active_record.rb +121 -48
- data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +34 -0
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +47 -0
- data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +12 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
- data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
- data/lib/rails/generators/active_record.rb +25 -0
- metadata +187 -363
- data/CHANGELOG +0 -5904
- data/README +0 -351
- data/RUNNING_UNIT_TESTS +0 -36
- data/Rakefile +0 -268
- data/install.rb +0 -30
- data/lib/active_record/association_preload.rb +0 -406
- data/lib/active_record/associations/association_collection.rb +0 -533
- data/lib/active_record/associations/association_proxy.rb +0 -288
- data/lib/active_record/batches.rb +0 -85
- data/lib/active_record/calculations.rb +0 -321
- data/lib/active_record/dirty.rb +0 -183
- data/lib/active_record/named_scope.rb +0 -197
- data/lib/active_record/serializers/json_serializer.rb +0 -91
- data/lib/activerecord.rb +0 -2
- data/test/assets/example.log +0 -1
- data/test/assets/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +0 -24
- data/test/cases/active_schema_test_mysql.rb +0 -122
- data/test/cases/active_schema_test_postgresql.rb +0 -24
- data/test/cases/adapter_test.rb +0 -144
- data/test/cases/aggregations_test.rb +0 -167
- data/test/cases/ar_schema_test.rb +0 -32
- data/test/cases/associations/belongs_to_associations_test.rb +0 -438
- data/test/cases/associations/callbacks_test.rb +0 -161
- data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
- data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
- data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
- data/test/cases/associations/eager_singularization_test.rb +0 -145
- data/test/cases/associations/eager_test.rb +0 -852
- data/test/cases/associations/extension_test.rb +0 -62
- data/test/cases/associations/habtm_join_table_test.rb +0 -56
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
- data/test/cases/associations/has_many_associations_test.rb +0 -1273
- data/test/cases/associations/has_many_through_associations_test.rb +0 -360
- data/test/cases/associations/has_one_associations_test.rb +0 -330
- data/test/cases/associations/has_one_through_associations_test.rb +0 -209
- data/test/cases/associations/inner_join_association_test.rb +0 -93
- data/test/cases/associations/inverse_associations_test.rb +0 -566
- data/test/cases/associations/join_model_test.rb +0 -712
- data/test/cases/associations_test.rb +0 -282
- data/test/cases/attribute_methods_test.rb +0 -305
- data/test/cases/autosave_association_test.rb +0 -1218
- data/test/cases/base_test.rb +0 -2166
- data/test/cases/batches_test.rb +0 -81
- data/test/cases/binary_test.rb +0 -30
- data/test/cases/calculations_test.rb +0 -360
- data/test/cases/callbacks_observers_test.rb +0 -38
- data/test/cases/callbacks_test.rb +0 -438
- data/test/cases/class_inheritable_attributes_test.rb +0 -32
- data/test/cases/column_alias_test.rb +0 -17
- data/test/cases/column_definition_test.rb +0 -70
- data/test/cases/connection_pool_test.rb +0 -25
- data/test/cases/connection_test_firebird.rb +0 -8
- data/test/cases/connection_test_mysql.rb +0 -65
- data/test/cases/copy_table_test_sqlite.rb +0 -80
- data/test/cases/counter_cache_test.rb +0 -84
- data/test/cases/database_statements_test.rb +0 -12
- data/test/cases/datatype_test_postgresql.rb +0 -204
- data/test/cases/date_time_test.rb +0 -37
- data/test/cases/default_test_firebird.rb +0 -16
- data/test/cases/defaults_test.rb +0 -111
- data/test/cases/deprecated_finder_test.rb +0 -30
- data/test/cases/dirty_test.rb +0 -316
- data/test/cases/finder_respond_to_test.rb +0 -76
- data/test/cases/finder_test.rb +0 -1098
- data/test/cases/fixtures_test.rb +0 -661
- data/test/cases/helper.rb +0 -68
- data/test/cases/i18n_test.rb +0 -46
- data/test/cases/inheritance_test.rb +0 -262
- data/test/cases/invalid_date_test.rb +0 -24
- data/test/cases/json_serialization_test.rb +0 -219
- data/test/cases/lifecycle_test.rb +0 -193
- data/test/cases/locking_test.rb +0 -350
- data/test/cases/method_scoping_test.rb +0 -704
- data/test/cases/migration_test.rb +0 -1649
- data/test/cases/migration_test_firebird.rb +0 -124
- data/test/cases/mixin_test.rb +0 -96
- data/test/cases/modules_test.rb +0 -109
- data/test/cases/multiple_db_test.rb +0 -85
- data/test/cases/named_scope_test.rb +0 -372
- data/test/cases/nested_attributes_test.rb +0 -840
- data/test/cases/pk_test.rb +0 -119
- data/test/cases/pooled_connections_test.rb +0 -103
- data/test/cases/query_cache_test.rb +0 -129
- data/test/cases/readonly_test.rb +0 -107
- data/test/cases/reflection_test.rb +0 -234
- data/test/cases/reload_models_test.rb +0 -22
- data/test/cases/repair_helper.rb +0 -50
- data/test/cases/reserved_word_test_mysql.rb +0 -176
- data/test/cases/sanitize_test.rb +0 -25
- data/test/cases/schema_authorization_test_postgresql.rb +0 -75
- data/test/cases/schema_dumper_test.rb +0 -211
- data/test/cases/schema_test_postgresql.rb +0 -178
- data/test/cases/serialization_test.rb +0 -47
- data/test/cases/sp_test_mysql.rb +0 -16
- data/test/cases/synonym_test_oracle.rb +0 -17
- data/test/cases/timestamp_test.rb +0 -75
- data/test/cases/transactions_test.rb +0 -543
- data/test/cases/unconnected_test.rb +0 -32
- data/test/cases/validations_i18n_test.rb +0 -925
- data/test/cases/validations_test.rb +0 -1684
- data/test/cases/xml_serialization_test.rb +0 -240
- data/test/cases/yaml_serialization_test.rb +0 -11
- data/test/config.rb +0 -5
- data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
- data/test/connections/jdbc_jdbch2/connection.rb +0 -18
- data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
- data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
- data/test/connections/native_db2/connection.rb +0 -25
- data/test/connections/native_firebird/connection.rb +0 -26
- data/test/connections/native_frontbase/connection.rb +0 -27
- data/test/connections/native_mysql/connection.rb +0 -25
- data/test/connections/native_openbase/connection.rb +0 -21
- data/test/connections/native_oracle/connection.rb +0 -27
- data/test/connections/native_postgresql/connection.rb +0 -21
- data/test/connections/native_sqlite/connection.rb +0 -25
- data/test/connections/native_sqlite3/connection.rb +0 -25
- data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
- data/test/connections/native_sybase/connection.rb +0 -23
- data/test/fixtures/accounts.yml +0 -29
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author_addresses.yml +0 -5
- data/test/fixtures/author_favorites.yml +0 -4
- data/test/fixtures/authors.yml +0 -9
- data/test/fixtures/binaries.yml +0 -132
- data/test/fixtures/books.yml +0 -7
- data/test/fixtures/categories/special_categories.yml +0 -9
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
- data/test/fixtures/categories.yml +0 -14
- data/test/fixtures/categories_ordered.yml +0 -7
- data/test/fixtures/categories_posts.yml +0 -23
- data/test/fixtures/categorizations.yml +0 -17
- data/test/fixtures/clubs.yml +0 -6
- data/test/fixtures/comments.yml +0 -59
- data/test/fixtures/companies.yml +0 -56
- data/test/fixtures/computers.yml +0 -4
- data/test/fixtures/courses.yml +0 -7
- data/test/fixtures/customers.yml +0 -26
- data/test/fixtures/developers.yml +0 -21
- data/test/fixtures/developers_projects.yml +0 -17
- data/test/fixtures/edges.yml +0 -6
- data/test/fixtures/entrants.yml +0 -14
- data/test/fixtures/faces.yml +0 -11
- data/test/fixtures/fk_test_has_fk.yml +0 -3
- data/test/fixtures/fk_test_has_pk.yml +0 -2
- data/test/fixtures/funny_jokes.yml +0 -10
- data/test/fixtures/interests.yml +0 -33
- data/test/fixtures/items.yml +0 -4
- data/test/fixtures/jobs.yml +0 -7
- data/test/fixtures/legacy_things.yml +0 -3
- data/test/fixtures/mateys.yml +0 -4
- data/test/fixtures/member_types.yml +0 -6
- data/test/fixtures/members.yml +0 -6
- data/test/fixtures/memberships.yml +0 -20
- data/test/fixtures/men.yml +0 -5
- data/test/fixtures/minimalistics.yml +0 -2
- data/test/fixtures/mixed_case_monkeys.yml +0 -6
- data/test/fixtures/mixins.yml +0 -29
- data/test/fixtures/movies.yml +0 -7
- data/test/fixtures/naked/csv/accounts.csv +0 -1
- data/test/fixtures/naked/yml/accounts.yml +0 -1
- data/test/fixtures/naked/yml/companies.yml +0 -1
- data/test/fixtures/naked/yml/courses.yml +0 -1
- data/test/fixtures/organizations.yml +0 -5
- data/test/fixtures/owners.yml +0 -7
- data/test/fixtures/parrots.yml +0 -27
- data/test/fixtures/parrots_pirates.yml +0 -7
- data/test/fixtures/people.yml +0 -15
- data/test/fixtures/pets.yml +0 -14
- data/test/fixtures/pirates.yml +0 -9
- data/test/fixtures/polymorphic_designs.yml +0 -19
- data/test/fixtures/polymorphic_prices.yml +0 -19
- data/test/fixtures/posts.yml +0 -52
- data/test/fixtures/price_estimates.yml +0 -7
- data/test/fixtures/projects.yml +0 -7
- data/test/fixtures/readers.yml +0 -9
- data/test/fixtures/references.yml +0 -17
- data/test/fixtures/reserved_words/distinct.yml +0 -5
- data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
- data/test/fixtures/reserved_words/group.yml +0 -14
- data/test/fixtures/reserved_words/select.yml +0 -8
- data/test/fixtures/reserved_words/values.yml +0 -7
- data/test/fixtures/ships.yml +0 -5
- data/test/fixtures/sponsors.yml +0 -9
- data/test/fixtures/subscribers.yml +0 -7
- data/test/fixtures/subscriptions.yml +0 -12
- data/test/fixtures/taggings.yml +0 -28
- data/test/fixtures/tags.yml +0 -7
- data/test/fixtures/tasks.yml +0 -7
- data/test/fixtures/tees.yml +0 -4
- data/test/fixtures/ties.yml +0 -4
- data/test/fixtures/topics.yml +0 -42
- data/test/fixtures/toys.yml +0 -4
- data/test/fixtures/treasures.yml +0 -10
- data/test/fixtures/vertices.yml +0 -4
- data/test/fixtures/warehouse-things.yml +0 -3
- data/test/fixtures/zines.yml +0 -5
- data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
- data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
- data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
- data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
- data/test/migrations/duplicate/3_foo.rb +0 -7
- data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
- data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
- data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
- data/test/migrations/missing/1_people_have_last_names.rb +0 -9
- data/test/migrations/missing/3_we_need_reminders.rb +0 -12
- data/test/migrations/missing/4_innocent_jointable.rb +0 -12
- data/test/migrations/valid/1_people_have_last_names.rb +0 -9
- data/test/migrations/valid/2_we_need_reminders.rb +0 -12
- data/test/migrations/valid/3_innocent_jointable.rb +0 -12
- data/test/models/author.rb +0 -151
- data/test/models/auto_id.rb +0 -4
- data/test/models/binary.rb +0 -2
- data/test/models/bird.rb +0 -9
- data/test/models/book.rb +0 -4
- data/test/models/categorization.rb +0 -5
- data/test/models/category.rb +0 -34
- data/test/models/citation.rb +0 -6
- data/test/models/club.rb +0 -13
- data/test/models/column_name.rb +0 -3
- data/test/models/comment.rb +0 -29
- data/test/models/company.rb +0 -173
- data/test/models/company_in_module.rb +0 -78
- data/test/models/computer.rb +0 -3
- data/test/models/contact.rb +0 -16
- data/test/models/contract.rb +0 -5
- data/test/models/course.rb +0 -3
- data/test/models/customer.rb +0 -73
- data/test/models/default.rb +0 -2
- data/test/models/developer.rb +0 -101
- data/test/models/edge.rb +0 -5
- data/test/models/entrant.rb +0 -3
- data/test/models/essay.rb +0 -3
- data/test/models/event.rb +0 -3
- data/test/models/event_author.rb +0 -8
- data/test/models/face.rb +0 -7
- data/test/models/guid.rb +0 -2
- data/test/models/interest.rb +0 -5
- data/test/models/invoice.rb +0 -4
- data/test/models/item.rb +0 -7
- data/test/models/job.rb +0 -5
- data/test/models/joke.rb +0 -3
- data/test/models/keyboard.rb +0 -3
- data/test/models/legacy_thing.rb +0 -3
- data/test/models/line_item.rb +0 -3
- data/test/models/man.rb +0 -9
- data/test/models/matey.rb +0 -4
- data/test/models/member.rb +0 -12
- data/test/models/member_detail.rb +0 -5
- data/test/models/member_type.rb +0 -3
- data/test/models/membership.rb +0 -9
- data/test/models/minimalistic.rb +0 -2
- data/test/models/mixed_case_monkey.rb +0 -3
- data/test/models/movie.rb +0 -5
- data/test/models/order.rb +0 -4
- data/test/models/organization.rb +0 -6
- data/test/models/owner.rb +0 -5
- data/test/models/parrot.rb +0 -22
- data/test/models/person.rb +0 -16
- data/test/models/pet.rb +0 -5
- data/test/models/pirate.rb +0 -80
- data/test/models/polymorphic_design.rb +0 -3
- data/test/models/polymorphic_price.rb +0 -3
- data/test/models/post.rb +0 -102
- data/test/models/price_estimate.rb +0 -3
- data/test/models/project.rb +0 -30
- data/test/models/reader.rb +0 -4
- data/test/models/reference.rb +0 -4
- data/test/models/reply.rb +0 -46
- data/test/models/ship.rb +0 -19
- data/test/models/ship_part.rb +0 -7
- data/test/models/sponsor.rb +0 -4
- data/test/models/subject.rb +0 -4
- data/test/models/subscriber.rb +0 -8
- data/test/models/subscription.rb +0 -4
- data/test/models/tag.rb +0 -7
- data/test/models/tagging.rb +0 -10
- data/test/models/task.rb +0 -3
- data/test/models/tee.rb +0 -4
- data/test/models/tie.rb +0 -4
- data/test/models/topic.rb +0 -80
- data/test/models/toy.rb +0 -6
- data/test/models/treasure.rb +0 -8
- data/test/models/vertex.rb +0 -9
- data/test/models/warehouse_thing.rb +0 -5
- data/test/models/zine.rb +0 -3
- data/test/schema/mysql_specific_schema.rb +0 -31
- data/test/schema/postgresql_specific_schema.rb +0 -114
- data/test/schema/schema.rb +0 -550
- data/test/schema/schema2.rb +0 -6
- data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -1,5 +1,11 @@
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
2
|
+
require "active_support/core_ext/class/attribute_accessors"
|
3
|
+
require "active_support/core_ext/array/wrap"
|
4
|
+
require 'active_support/deprecation'
|
5
|
+
|
1
6
|
module ActiveRecord
|
2
|
-
|
7
|
+
# Exception that can be raised to stop migrations from going backwards.
|
8
|
+
class IrreversibleMigration < ActiveRecordError
|
3
9
|
end
|
4
10
|
|
5
11
|
class DuplicateMigrationVersionError < ActiveRecordError#:nodoc:
|
@@ -26,111 +32,139 @@ module ActiveRecord
|
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
35
|
+
# = Active Record Migrations
|
36
|
+
#
|
37
|
+
# Migrations can manage the evolution of a schema used by several physical
|
38
|
+
# databases. It's a solution to the common problem of adding a field to make
|
39
|
+
# a new feature work in your local database, but being unsure of how to
|
40
|
+
# push that change to other developers and to the production server. With
|
41
|
+
# migrations, you can describe the transformations in self-contained classes
|
42
|
+
# that can be checked into version control systems and executed against
|
43
|
+
# another database that might be one, two, or five versions behind.
|
34
44
|
#
|
35
45
|
# Example of a simple migration:
|
36
46
|
#
|
37
47
|
# class AddSsl < ActiveRecord::Migration
|
38
|
-
# def
|
48
|
+
# def up
|
39
49
|
# add_column :accounts, :ssl_enabled, :boolean, :default => 1
|
40
50
|
# end
|
41
51
|
#
|
42
|
-
# def
|
52
|
+
# def down
|
43
53
|
# remove_column :accounts, :ssl_enabled
|
44
54
|
# end
|
45
55
|
# end
|
46
56
|
#
|
47
|
-
# This migration will add a boolean flag to the accounts table and remove it
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
57
|
+
# This migration will add a boolean flag to the accounts table and remove it
|
58
|
+
# if you're backing out of the migration. It shows how all migrations have
|
59
|
+
# two methods +up+ and +down+ that describes the transformations
|
60
|
+
# required to implement or remove the migration. These methods can consist
|
61
|
+
# of both the migration specific methods like add_column and remove_column,
|
62
|
+
# but may also contain regular Ruby code for generating data needed for the
|
63
|
+
# transformations.
|
51
64
|
#
|
52
65
|
# Example of a more complex migration that also needs to initialize data:
|
53
66
|
#
|
54
67
|
# class AddSystemSettings < ActiveRecord::Migration
|
55
|
-
# def
|
68
|
+
# def up
|
56
69
|
# create_table :system_settings do |t|
|
57
70
|
# t.string :name
|
58
71
|
# t.string :label
|
59
|
-
# t.text
|
72
|
+
# t.text :value
|
60
73
|
# t.string :type
|
61
|
-
# t.integer
|
74
|
+
# t.integer :position
|
62
75
|
# end
|
63
76
|
#
|
64
|
-
# SystemSetting.create
|
77
|
+
# SystemSetting.create :name => "notice",
|
78
|
+
# :label => "Use notice?",
|
79
|
+
# :value => 1
|
65
80
|
# end
|
66
81
|
#
|
67
|
-
# def
|
82
|
+
# def down
|
68
83
|
# drop_table :system_settings
|
69
84
|
# end
|
70
85
|
# end
|
71
86
|
#
|
72
|
-
# This migration first adds the system_settings table, then creates the very
|
73
|
-
#
|
74
|
-
#
|
87
|
+
# This migration first adds the system_settings table, then creates the very
|
88
|
+
# first row in it using the Active Record model that relies on the table. It
|
89
|
+
# also uses the more advanced create_table syntax where you can specify a
|
90
|
+
# complete table schema in one block call.
|
75
91
|
#
|
76
92
|
# == Available transformations
|
77
93
|
#
|
78
|
-
# * <tt>create_table(name, options)</tt> Creates a table called +name+ and
|
79
|
-
#
|
80
|
-
#
|
94
|
+
# * <tt>create_table(name, options)</tt> Creates a table called +name+ and
|
95
|
+
# makes the table object available to a block that can then add columns to it,
|
96
|
+
# following the same format as add_column. See example above. The options hash
|
97
|
+
# is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
|
98
|
+
# table definition.
|
81
99
|
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
|
82
|
-
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
|
83
|
-
#
|
100
|
+
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
|
101
|
+
# to +new_name+.
|
102
|
+
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
|
103
|
+
# to the table called +table_name+
|
84
104
|
# named +column_name+ specified to be one of the following types:
|
85
|
-
# <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
|
86
|
-
# <tt>:
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
# * <tt>
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
105
|
+
# <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
|
106
|
+
# <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
|
107
|
+
# <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be
|
108
|
+
# specified by passing an +options+ hash like <tt>{ :default => 11 }</tt>.
|
109
|
+
# Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
|
110
|
+
# <tt>{ :limit => 50, :null => false }</tt>) -- see
|
111
|
+
# ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
|
112
|
+
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
|
113
|
+
# a column but keeps the type and content.
|
114
|
+
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
|
115
|
+
# the column to a different type using the same parameters as add_column.
|
116
|
+
# * <tt>remove_column(table_name, column_names)</tt>: Removes the column listed in
|
117
|
+
# +column_names+ from the table called +table_name+.
|
118
|
+
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
|
119
|
+
# with the name of the column. Other options include
|
120
|
+
# <tt>:name</tt>, <tt>:unique</tt> (e.g.
|
121
|
+
# <tt>{ :name => "users_name_index", :unique => true }</tt>) and <tt>:order</tt>
|
122
|
+
# (e.g. { :order => {:name => :desc} }</tt>).
|
123
|
+
# * <tt>remove_index(table_name, :column => column_name)</tt>: Removes the index
|
124
|
+
# specified by +column_name+.
|
125
|
+
# * <tt>remove_index(table_name, :name => index_name)</tt>: Removes the index
|
126
|
+
# specified by +index_name+.
|
96
127
|
#
|
97
128
|
# == Irreversible transformations
|
98
129
|
#
|
99
|
-
# Some transformations are destructive in a manner that cannot be reversed.
|
100
|
-
# an <tt>ActiveRecord::IrreversibleMigration</tt>
|
130
|
+
# Some transformations are destructive in a manner that cannot be reversed.
|
131
|
+
# Migrations of that kind should raise an <tt>ActiveRecord::IrreversibleMigration</tt>
|
132
|
+
# exception in their +down+ method.
|
101
133
|
#
|
102
134
|
# == Running migrations from within Rails
|
103
135
|
#
|
104
136
|
# The Rails package has several tools to help create and apply migrations.
|
105
137
|
#
|
106
|
-
# To generate a new migration, you can use
|
107
|
-
#
|
138
|
+
# To generate a new migration, you can use
|
139
|
+
# rails generate migration MyNewMigration
|
108
140
|
#
|
109
141
|
# where MyNewMigration is the name of your migration. The generator will
|
110
|
-
# create an empty migration file <tt>
|
111
|
-
# directory where <tt>
|
142
|
+
# create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
|
143
|
+
# in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
|
144
|
+
# UTC formatted date and time that the migration was generated.
|
112
145
|
#
|
113
|
-
# You may then edit the <tt>
|
146
|
+
# You may then edit the <tt>up</tt> and <tt>down</tt> methods of
|
114
147
|
# MyNewMigration.
|
115
148
|
#
|
116
149
|
# There is a special syntactic shortcut to generate migrations that add fields to a table.
|
117
|
-
# script/generate migration add_fieldname_to_tablename fieldname:string
|
118
150
|
#
|
119
|
-
#
|
151
|
+
# rails generate migration add_fieldname_to_tablename fieldname:string
|
152
|
+
#
|
153
|
+
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
|
120
154
|
# class AddFieldnameToTablename < ActiveRecord::Migration
|
121
|
-
# def
|
155
|
+
# def up
|
122
156
|
# add_column :tablenames, :fieldname, :string
|
123
157
|
# end
|
124
|
-
#
|
125
|
-
# def
|
158
|
+
#
|
159
|
+
# def down
|
126
160
|
# remove_column :tablenames, :fieldname
|
127
161
|
# end
|
128
162
|
# end
|
129
|
-
#
|
163
|
+
#
|
130
164
|
# To run migrations against the currently configured database, use
|
131
165
|
# <tt>rake db:migrate</tt>. This will update the database by running all of the
|
132
166
|
# pending migrations, creating the <tt>schema_migrations</tt> table
|
133
|
-
# (see "About the schema_migrations table" section below) if missing. It will also
|
167
|
+
# (see "About the schema_migrations table" section below) if missing. It will also
|
134
168
|
# invoke the db:schema:dump task, which will update your db/schema.rb file
|
135
169
|
# to match the structure of your database.
|
136
170
|
#
|
@@ -150,11 +184,11 @@ module ActiveRecord
|
|
150
184
|
# Not all migrations change the schema. Some just fix the data:
|
151
185
|
#
|
152
186
|
# class RemoveEmptyTags < ActiveRecord::Migration
|
153
|
-
# def
|
154
|
-
# Tag.
|
187
|
+
# def up
|
188
|
+
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
155
189
|
# end
|
156
190
|
#
|
157
|
-
# def
|
191
|
+
# def down
|
158
192
|
# # not much we can do to restore deleted data
|
159
193
|
# raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
|
160
194
|
# end
|
@@ -163,12 +197,12 @@ module ActiveRecord
|
|
163
197
|
# Others remove columns when they migrate up instead of down:
|
164
198
|
#
|
165
199
|
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
|
166
|
-
# def
|
200
|
+
# def up
|
167
201
|
# remove_column :items, :incomplete_items_count
|
168
202
|
# remove_column :items, :completed_items_count
|
169
203
|
# end
|
170
204
|
#
|
171
|
-
# def
|
205
|
+
# def down
|
172
206
|
# add_column :items, :incomplete_items_count
|
173
207
|
# add_column :items, :completed_items_count
|
174
208
|
# end
|
@@ -177,26 +211,27 @@ module ActiveRecord
|
|
177
211
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
178
212
|
#
|
179
213
|
# class MakeJoinUnique < ActiveRecord::Migration
|
180
|
-
# def
|
214
|
+
# def up
|
181
215
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
182
216
|
# end
|
183
217
|
#
|
184
|
-
# def
|
218
|
+
# def down
|
185
219
|
# execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
|
186
220
|
# end
|
187
221
|
# end
|
188
222
|
#
|
189
223
|
# == Using a model after changing its table
|
190
224
|
#
|
191
|
-
# Sometimes you'll want to add a column in a migration and populate it
|
192
|
-
#
|
193
|
-
#
|
225
|
+
# Sometimes you'll want to add a column in a migration and populate it
|
226
|
+
# immediately after. In that case, you'll need to make a call to
|
227
|
+
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
228
|
+
# latest column data from after the new column was added. Example:
|
194
229
|
#
|
195
230
|
# class AddPeopleSalary < ActiveRecord::Migration
|
196
|
-
# def
|
231
|
+
# def up
|
197
232
|
# add_column :people, :salary, :integer
|
198
233
|
# Person.reset_column_information
|
199
|
-
# Person.
|
234
|
+
# Person.all.each do |p|
|
200
235
|
# p.update_attribute :salary, SalaryCalculator.compute(p)
|
201
236
|
# end
|
202
237
|
# end
|
@@ -213,10 +248,10 @@ module ActiveRecord
|
|
213
248
|
# You can also insert your own messages and benchmarks by using the +say_with_time+
|
214
249
|
# method:
|
215
250
|
#
|
216
|
-
# def
|
251
|
+
# def up
|
217
252
|
# ...
|
218
253
|
# say_with_time "Updating salaries..." do
|
219
|
-
# Person.
|
254
|
+
# Person.all.each do |p|
|
220
255
|
# p.update_attribute :salary, SalaryCalculator.compute(p)
|
221
256
|
# end
|
222
257
|
# end
|
@@ -240,7 +275,7 @@ module ActiveRecord
|
|
240
275
|
# lower than the current schema version: when migrating up, those
|
241
276
|
# never-applied "interleaved" migrations will be automatically applied, and
|
242
277
|
# when migrating down, never-applied "interleaved" migrations will be skipped.
|
243
|
-
#
|
278
|
+
#
|
244
279
|
# == Timestamped Migrations
|
245
280
|
#
|
246
281
|
# By default, Rails generates migrations that look like:
|
@@ -253,115 +288,244 @@ module ActiveRecord
|
|
253
288
|
# off by setting:
|
254
289
|
#
|
255
290
|
# config.active_record.timestamped_migrations = false
|
256
|
-
#
|
257
|
-
# In environment.rb.
|
258
291
|
#
|
292
|
+
# In application.rb.
|
293
|
+
#
|
294
|
+
# == Reversible Migrations
|
295
|
+
#
|
296
|
+
# Starting with Rails 3.1, you will be able to define reversible migrations.
|
297
|
+
# Reversible migrations are migrations that know how to go +down+ for you.
|
298
|
+
# You simply supply the +up+ logic, and the Migration system will figure out
|
299
|
+
# how to execute the down commands for you.
|
300
|
+
#
|
301
|
+
# To define a reversible migration, define the +change+ method in your
|
302
|
+
# migration like this:
|
303
|
+
#
|
304
|
+
# class TenderloveMigration < ActiveRecord::Migration
|
305
|
+
# def change
|
306
|
+
# create_table(:horses) do |t|
|
307
|
+
# t.column :content, :text
|
308
|
+
# t.column :remind_at, :datetime
|
309
|
+
# end
|
310
|
+
# end
|
311
|
+
# end
|
312
|
+
#
|
313
|
+
# This migration will create the horses table for you on the way up, and
|
314
|
+
# automatically figure out how to drop the table on the way down.
|
315
|
+
#
|
316
|
+
# Some commands like +remove_column+ cannot be reversed. If you care to
|
317
|
+
# define how to move up and down in these cases, you should define the +up+
|
318
|
+
# and +down+ methods as before.
|
319
|
+
#
|
320
|
+
# If a command cannot be reversed, an
|
321
|
+
# <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
|
322
|
+
# the migration is moving down.
|
323
|
+
#
|
324
|
+
# For a list of commands that are reversible, please see
|
325
|
+
# <tt>ActiveRecord::Migration::CommandRecorder</tt>.
|
259
326
|
class Migration
|
260
|
-
|
261
|
-
cattr_accessor :verbose
|
327
|
+
autoload :CommandRecorder, 'active_record/migration/command_recorder'
|
262
328
|
|
263
329
|
class << self
|
264
|
-
|
265
|
-
|
266
|
-
end
|
330
|
+
attr_accessor :delegate # :nodoc:
|
331
|
+
end
|
267
332
|
|
268
|
-
|
269
|
-
|
270
|
-
|
333
|
+
def self.method_missing(name, *args, &block) # :nodoc:
|
334
|
+
(delegate || superclass.delegate).send(name, *args, &block)
|
335
|
+
end
|
271
336
|
|
272
|
-
|
273
|
-
|
274
|
-
|
337
|
+
def self.migrate(direction)
|
338
|
+
new.migrate direction
|
339
|
+
end
|
275
340
|
|
276
|
-
|
277
|
-
when :up then announce "migrating"
|
278
|
-
when :down then announce "reverting"
|
279
|
-
end
|
341
|
+
cattr_accessor :verbose
|
280
342
|
|
281
|
-
|
282
|
-
time = Benchmark.measure { result = send("#{direction}_without_benchmarks") }
|
343
|
+
attr_accessor :name, :version
|
283
344
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
345
|
+
def initialize
|
346
|
+
@name = self.class.name
|
347
|
+
@version = nil
|
348
|
+
@connection = nil
|
349
|
+
@reverting = false
|
350
|
+
end
|
288
351
|
|
289
|
-
|
290
|
-
|
352
|
+
# instantiate the delegate object after initialize is defined
|
353
|
+
self.verbose = true
|
354
|
+
self.delegate = new
|
291
355
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
356
|
+
def revert
|
357
|
+
@reverting = true
|
358
|
+
yield
|
359
|
+
ensure
|
360
|
+
@reverting = false
|
361
|
+
end
|
297
362
|
|
298
|
-
|
299
|
-
|
363
|
+
def reverting?
|
364
|
+
@reverting
|
365
|
+
end
|
366
|
+
|
367
|
+
def up
|
368
|
+
self.class.delegate = self
|
369
|
+
return unless self.class.respond_to?(:up)
|
370
|
+
self.class.up
|
371
|
+
end
|
372
|
+
|
373
|
+
def down
|
374
|
+
self.class.delegate = self
|
375
|
+
return unless self.class.respond_to?(:down)
|
376
|
+
self.class.down
|
377
|
+
end
|
378
|
+
|
379
|
+
# Execute this migration in the named direction
|
380
|
+
def migrate(direction)
|
381
|
+
return unless respond_to?(direction)
|
382
|
+
|
383
|
+
case direction
|
384
|
+
when :up then announce "migrating"
|
385
|
+
when :down then announce "reverting"
|
386
|
+
end
|
300
387
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
388
|
+
time = nil
|
389
|
+
ActiveRecord::Base.connection_pool.with_connection do |conn|
|
390
|
+
@connection = conn
|
391
|
+
if respond_to?(:change)
|
392
|
+
if direction == :down
|
393
|
+
recorder = CommandRecorder.new(@connection)
|
394
|
+
suppress_messages do
|
395
|
+
@connection = recorder
|
396
|
+
change
|
397
|
+
end
|
398
|
+
@connection = conn
|
399
|
+
time = Benchmark.measure {
|
400
|
+
self.revert {
|
401
|
+
recorder.inverse.each do |cmd, args|
|
402
|
+
send(cmd, *args)
|
403
|
+
end
|
404
|
+
}
|
405
|
+
}
|
406
|
+
else
|
407
|
+
time = Benchmark.measure { change }
|
305
408
|
end
|
306
|
-
|
307
|
-
|
409
|
+
else
|
410
|
+
time = Benchmark.measure { send(direction) }
|
308
411
|
end
|
412
|
+
@connection = nil
|
309
413
|
end
|
310
414
|
|
311
|
-
|
312
|
-
|
415
|
+
case direction
|
416
|
+
when :up then announce "migrated (%.4fs)" % time.real; write
|
417
|
+
when :down then announce "reverted (%.4fs)" % time.real; write
|
313
418
|
end
|
419
|
+
end
|
314
420
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
write "== %s %s" % [text, "=" * length]
|
319
|
-
end
|
421
|
+
def write(text="")
|
422
|
+
puts(text) if verbose
|
423
|
+
end
|
320
424
|
|
321
|
-
|
322
|
-
|
323
|
-
|
425
|
+
def announce(message)
|
426
|
+
text = "#{version} #{name}: #{message}"
|
427
|
+
length = [0, 75 - text.length].max
|
428
|
+
write "== %s %s" % [text, "=" * length]
|
429
|
+
end
|
324
430
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
time = Benchmark.measure { result = yield }
|
329
|
-
say "%.4fs" % time.real, :subitem
|
330
|
-
say("#{result} rows", :subitem) if result.is_a?(Integer)
|
331
|
-
result
|
332
|
-
end
|
431
|
+
def say(message, subitem=false)
|
432
|
+
write "#{subitem ? " ->" : "--"} #{message}"
|
433
|
+
end
|
333
434
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
435
|
+
def say_with_time(message)
|
436
|
+
say(message)
|
437
|
+
result = nil
|
438
|
+
time = Benchmark.measure { result = yield }
|
439
|
+
say "%.4fs" % time.real, :subitem
|
440
|
+
say("#{result} rows", :subitem) if result.is_a?(Integer)
|
441
|
+
result
|
442
|
+
end
|
340
443
|
|
341
|
-
|
342
|
-
|
343
|
-
|
444
|
+
def suppress_messages
|
445
|
+
save, self.verbose = verbose, false
|
446
|
+
yield
|
447
|
+
ensure
|
448
|
+
self.verbose = save
|
449
|
+
end
|
450
|
+
|
451
|
+
def connection
|
452
|
+
@connection || ActiveRecord::Base.connection
|
453
|
+
end
|
344
454
|
|
345
|
-
|
346
|
-
|
455
|
+
def method_missing(method, *arguments, &block)
|
456
|
+
arg_list = arguments.map{ |a| a.inspect } * ', '
|
347
457
|
|
348
|
-
|
458
|
+
say_with_time "#{method}(#{arg_list})" do
|
459
|
+
unless reverting?
|
349
460
|
unless arguments.empty? || method == :execute
|
350
|
-
arguments[0] = Migrator.proper_table_name(arguments.first)
|
461
|
+
arguments[0] = Migrator.proper_table_name(arguments.first) unless method == :assume_migrated_upto_version
|
462
|
+
arguments[1] = Migrator.proper_table_name(arguments.second) if method == :rename_table
|
351
463
|
end
|
352
|
-
connection.send(method, *arguments, &block)
|
353
464
|
end
|
465
|
+
return super unless connection.respond_to?(method)
|
466
|
+
connection.send(method, *arguments, &block)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
def copy(destination, sources, options = {})
|
471
|
+
copied = []
|
472
|
+
|
473
|
+
FileUtils.mkdir_p(destination) unless File.exists?(destination)
|
474
|
+
|
475
|
+
destination_migrations = ActiveRecord::Migrator.migrations(destination)
|
476
|
+
last = destination_migrations.last
|
477
|
+
sources.each do |scope, path|
|
478
|
+
source_migrations = ActiveRecord::Migrator.migrations(path)
|
479
|
+
|
480
|
+
source_migrations.each do |migration|
|
481
|
+
source = File.read(migration.filename)
|
482
|
+
source = "# This migration comes from #{scope} (originally #{migration.version})\n#{source}"
|
483
|
+
|
484
|
+
if duplicate = destination_migrations.detect { |m| m.name == migration.name }
|
485
|
+
if options[:on_skip] && duplicate.scope != scope.to_s
|
486
|
+
options[:on_skip].call(scope, migration)
|
487
|
+
end
|
488
|
+
next
|
489
|
+
end
|
490
|
+
|
491
|
+
migration.version = next_migration_number(last ? last.version + 1 : 0).to_i
|
492
|
+
new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.#{scope}.rb")
|
493
|
+
old_path, migration.filename = migration.filename, new_path
|
494
|
+
last = migration
|
495
|
+
|
496
|
+
File.open(migration.filename, "w") { |f| f.write source }
|
497
|
+
copied << migration
|
498
|
+
options[:on_copy].call(scope, migration, old_path) if options[:on_copy]
|
499
|
+
destination_migrations << migration
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
copied
|
504
|
+
end
|
505
|
+
|
506
|
+
def next_migration_number(number)
|
507
|
+
if ActiveRecord::Base.timestamped_migrations
|
508
|
+
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
|
509
|
+
else
|
510
|
+
"%.3d" % number
|
354
511
|
end
|
355
512
|
end
|
356
513
|
end
|
357
514
|
|
358
515
|
# MigrationProxy is used to defer loading of the actual migration classes
|
359
516
|
# until they are needed
|
360
|
-
class MigrationProxy
|
517
|
+
class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
|
361
518
|
|
362
|
-
|
519
|
+
def initialize(name, version, filename, scope)
|
520
|
+
super
|
521
|
+
@migration = nil
|
522
|
+
end
|
523
|
+
|
524
|
+
def basename
|
525
|
+
File.basename(filename)
|
526
|
+
end
|
363
527
|
|
364
|
-
delegate :migrate, :announce, :write, :to
|
528
|
+
delegate :migrate, :announce, :write, :to => :migration
|
365
529
|
|
366
530
|
private
|
367
531
|
|
@@ -370,47 +534,48 @@ module ActiveRecord
|
|
370
534
|
end
|
371
535
|
|
372
536
|
def load_migration
|
373
|
-
|
374
|
-
name.constantize
|
537
|
+
require(File.expand_path(filename))
|
538
|
+
name.constantize.new
|
375
539
|
end
|
376
540
|
|
377
541
|
end
|
378
542
|
|
379
543
|
class Migrator#:nodoc:
|
380
544
|
class << self
|
381
|
-
|
545
|
+
attr_writer :migrations_paths
|
546
|
+
alias :migrations_path= :migrations_paths=
|
547
|
+
|
548
|
+
def migrate(migrations_paths, target_version = nil, &block)
|
382
549
|
case
|
383
|
-
when target_version.nil?
|
384
|
-
|
385
|
-
when current_version
|
386
|
-
|
550
|
+
when target_version.nil?
|
551
|
+
up(migrations_paths, target_version, &block)
|
552
|
+
when current_version == 0 && target_version == 0
|
553
|
+
[]
|
554
|
+
when current_version > target_version
|
555
|
+
down(migrations_paths, target_version, &block)
|
556
|
+
else
|
557
|
+
up(migrations_paths, target_version, &block)
|
387
558
|
end
|
388
559
|
end
|
389
560
|
|
390
|
-
def rollback(
|
391
|
-
|
392
|
-
start_index = migrator.migrations.index(migrator.current_migration)
|
393
|
-
|
394
|
-
return unless start_index
|
395
|
-
|
396
|
-
finish = migrator.migrations[start_index + steps]
|
397
|
-
down(migrations_path, finish ? finish.version : 0)
|
561
|
+
def rollback(migrations_paths, steps=1)
|
562
|
+
move(:down, migrations_paths, steps)
|
398
563
|
end
|
399
564
|
|
400
|
-
def
|
401
|
-
|
565
|
+
def forward(migrations_paths, steps=1)
|
566
|
+
move(:up, migrations_paths, steps)
|
402
567
|
end
|
403
568
|
|
404
|
-
def
|
405
|
-
self.new(:
|
569
|
+
def up(migrations_paths, target_version = nil, &block)
|
570
|
+
self.new(:up, migrations_paths, target_version).migrate(&block)
|
406
571
|
end
|
407
|
-
|
408
|
-
def
|
409
|
-
self.new(
|
572
|
+
|
573
|
+
def down(migrations_paths, target_version = nil, &block)
|
574
|
+
self.new(:down, migrations_paths, target_version).migrate(&block)
|
410
575
|
end
|
411
576
|
|
412
|
-
def
|
413
|
-
|
577
|
+
def run(direction, migrations_paths, target_version)
|
578
|
+
self.new(direction, migrations_paths, target_version).run
|
414
579
|
end
|
415
580
|
|
416
581
|
def schema_migrations_table_name
|
@@ -418,7 +583,8 @@ module ActiveRecord
|
|
418
583
|
end
|
419
584
|
|
420
585
|
def get_all_versions
|
421
|
-
|
586
|
+
table = Arel::Table.new(schema_migrations_table_name)
|
587
|
+
Base.connection.select_values(table.project(table['version'])).map{ |v| v.to_i }.sort
|
422
588
|
end
|
423
589
|
|
424
590
|
def current_version
|
@@ -434,22 +600,78 @@ module ActiveRecord
|
|
434
600
|
# Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
|
435
601
|
name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
|
436
602
|
end
|
603
|
+
|
604
|
+
def migrations_paths
|
605
|
+
@migrations_paths ||= ['db/migrate']
|
606
|
+
# just to not break things if someone uses: migration_path = some_string
|
607
|
+
Array.wrap(@migrations_paths)
|
608
|
+
end
|
609
|
+
|
610
|
+
def migrations_path
|
611
|
+
migrations_paths.first
|
612
|
+
end
|
613
|
+
|
614
|
+
def migrations(paths, *args)
|
615
|
+
if args.empty?
|
616
|
+
subdirectories = true
|
617
|
+
else
|
618
|
+
subdirectories = args.first
|
619
|
+
ActiveSupport::Deprecation.warn "The `subdirectories` argument to `migrations` is deprecated"
|
620
|
+
end
|
621
|
+
|
622
|
+
paths = Array.wrap(paths)
|
623
|
+
|
624
|
+
glob = subdirectories ? "**/" : ""
|
625
|
+
files = Dir[*paths.map { |p| "#{p}/#{glob}[0-9]*_*.rb" }]
|
626
|
+
|
627
|
+
seen = Hash.new false
|
628
|
+
|
629
|
+
migrations = files.map do |file|
|
630
|
+
version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
|
631
|
+
|
632
|
+
raise IllegalMigrationNameError.new(file) unless version
|
633
|
+
version = version.to_i
|
634
|
+
name = name.camelize
|
635
|
+
|
636
|
+
raise DuplicateMigrationVersionError.new(version) if seen[version]
|
637
|
+
raise DuplicateMigrationNameError.new(name) if seen[name]
|
638
|
+
|
639
|
+
seen[version] = seen[name] = true
|
640
|
+
|
641
|
+
MigrationProxy.new(name, version, file, scope)
|
642
|
+
end
|
643
|
+
|
644
|
+
migrations.sort_by(&:version)
|
645
|
+
end
|
646
|
+
|
647
|
+
private
|
648
|
+
|
649
|
+
def move(direction, migrations_paths, steps)
|
650
|
+
migrator = self.new(direction, migrations_paths)
|
651
|
+
start_index = migrator.migrations.index(migrator.current_migration)
|
652
|
+
|
653
|
+
if start_index
|
654
|
+
finish = migrator.migrations[start_index + steps]
|
655
|
+
version = finish ? finish.version : 0
|
656
|
+
send(direction, migrations_paths, version)
|
657
|
+
end
|
658
|
+
end
|
437
659
|
end
|
438
660
|
|
439
|
-
def initialize(direction,
|
661
|
+
def initialize(direction, migrations_paths, target_version = nil)
|
440
662
|
raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
|
441
663
|
Base.connection.initialize_schema_migrations_table
|
442
|
-
@direction, @
|
664
|
+
@direction, @migrations_paths, @target_version = direction, migrations_paths, target_version
|
443
665
|
end
|
444
666
|
|
445
667
|
def current_version
|
446
668
|
migrated.last || 0
|
447
669
|
end
|
448
|
-
|
670
|
+
|
449
671
|
def current_migration
|
450
672
|
migrations.detect { |m| m.version == current_version }
|
451
673
|
end
|
452
|
-
|
674
|
+
|
453
675
|
def run
|
454
676
|
target = migrations.detect { |m| m.version == @target_version }
|
455
677
|
raise UnknownMigrationVersionError.new(@target_version) if target.nil?
|
@@ -459,29 +681,36 @@ module ActiveRecord
|
|
459
681
|
end
|
460
682
|
end
|
461
683
|
|
462
|
-
def migrate
|
684
|
+
def migrate(&block)
|
463
685
|
current = migrations.detect { |m| m.version == current_version }
|
464
686
|
target = migrations.detect { |m| m.version == @target_version }
|
465
687
|
|
466
|
-
if target.nil? &&
|
688
|
+
if target.nil? && @target_version && @target_version > 0
|
467
689
|
raise UnknownMigrationVersionError.new(@target_version)
|
468
690
|
end
|
469
|
-
|
691
|
+
|
470
692
|
start = up? ? 0 : (migrations.index(current) || 0)
|
471
693
|
finish = migrations.index(target) || migrations.size - 1
|
472
694
|
runnable = migrations[start..finish]
|
473
|
-
|
695
|
+
|
474
696
|
# skip the last migration if we're headed down, but not ALL the way down
|
475
|
-
runnable.pop if down? &&
|
476
|
-
|
697
|
+
runnable.pop if down? && target
|
698
|
+
|
699
|
+
ran = []
|
477
700
|
runnable.each do |migration|
|
478
|
-
|
701
|
+
if block && !block.call(migration)
|
702
|
+
next
|
703
|
+
end
|
704
|
+
|
705
|
+
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
706
|
+
|
707
|
+
seen = migrated.include?(migration.version.to_i)
|
479
708
|
|
480
709
|
# On our way up, we skip migrating the ones we've already migrated
|
481
|
-
next if up? &&
|
710
|
+
next if up? && seen
|
482
711
|
|
483
712
|
# On our way down, we skip reverting the ones we've never migrated
|
484
|
-
if down? && !
|
713
|
+
if down? && !seen
|
485
714
|
migration.announce 'never migrated, skipping'; migration.write
|
486
715
|
next
|
487
716
|
end
|
@@ -491,39 +720,18 @@ module ActiveRecord
|
|
491
720
|
migration.migrate(@direction)
|
492
721
|
record_version_state_after_migrating(migration.version)
|
493
722
|
end
|
723
|
+
ran << migration
|
494
724
|
rescue => e
|
495
725
|
canceled_msg = Base.connection.supports_ddl_transactions? ? "this and " : ""
|
496
726
|
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
|
497
727
|
end
|
498
728
|
end
|
729
|
+
ran
|
499
730
|
end
|
500
731
|
|
501
732
|
def migrations
|
502
733
|
@migrations ||= begin
|
503
|
-
|
504
|
-
|
505
|
-
migrations = files.inject([]) do |klasses, file|
|
506
|
-
version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
|
507
|
-
|
508
|
-
raise IllegalMigrationNameError.new(file) unless version
|
509
|
-
version = version.to_i
|
510
|
-
|
511
|
-
if klasses.detect { |m| m.version == version }
|
512
|
-
raise DuplicateMigrationVersionError.new(version)
|
513
|
-
end
|
514
|
-
|
515
|
-
if klasses.detect { |m| m.name == name.camelize }
|
516
|
-
raise DuplicateMigrationNameError.new(name.camelize)
|
517
|
-
end
|
518
|
-
|
519
|
-
klasses << (MigrationProxy.new).tap do |migration|
|
520
|
-
migration.name = name.camelize
|
521
|
-
migration.version = version
|
522
|
-
migration.filename = file
|
523
|
-
end
|
524
|
-
end
|
525
|
-
|
526
|
-
migrations = migrations.sort_by(&:version)
|
734
|
+
migrations = self.class.migrations(@migrations_paths)
|
527
735
|
down? ? migrations.reverse : migrations
|
528
736
|
end
|
529
737
|
end
|
@@ -539,15 +747,17 @@ module ActiveRecord
|
|
539
747
|
|
540
748
|
private
|
541
749
|
def record_version_state_after_migrating(version)
|
542
|
-
|
750
|
+
table = Arel::Table.new(self.class.schema_migrations_table_name)
|
543
751
|
|
544
752
|
@migrated_versions ||= []
|
545
753
|
if down?
|
546
|
-
@migrated_versions.delete(version
|
547
|
-
|
754
|
+
@migrated_versions.delete(version)
|
755
|
+
stmt = table.where(table["version"].eq(version.to_s)).compile_delete
|
756
|
+
Base.connection.delete stmt
|
548
757
|
else
|
549
|
-
@migrated_versions.push(version
|
550
|
-
|
758
|
+
@migrated_versions.push(version).sort!
|
759
|
+
stmt = table.compile_insert table["version"] => version.to_s
|
760
|
+
Base.connection.insert stmt
|
551
761
|
end
|
552
762
|
end
|
553
763
|
|