activerecord 1.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (255) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2102 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +213 -0
  5. data/examples/performance.rb +172 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +180 -84
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +248 -0
  10. data/lib/active_record/associations/association_scope.rb +135 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +92 -0
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +35 -0
  13. data/lib/active_record/associations/builder/association.rb +108 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +98 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +89 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
  17. data/lib/active_record/associations/builder/has_many.rb +15 -0
  18. data/lib/active_record/associations/builder/has_one.rb +25 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +608 -0
  21. data/lib/active_record/associations/collection_proxy.rb +986 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +58 -39
  23. data/lib/active_record/associations/has_many_association.rb +116 -85
  24. data/lib/active_record/associations/has_many_through_association.rb +197 -0
  25. data/lib/active_record/associations/has_one_association.rb +102 -0
  26. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  27. data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +235 -0
  31. data/lib/active_record/associations/join_helper.rb +45 -0
  32. data/lib/active_record/associations/preloader/association.rb +121 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +63 -0
  42. data/lib/active_record/associations/preloader.rb +178 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +1437 -431
  46. data/lib/active_record/attribute_assignment.rb +201 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +70 -0
  48. data/lib/active_record/attribute_methods/dirty.rb +118 -0
  49. data/lib/active_record/attribute_methods/primary_key.rb +122 -0
  50. data/lib/active_record/attribute_methods/query.rb +40 -0
  51. data/lib/active_record/attribute_methods/read.rb +107 -0
  52. data/lib/active_record/attribute_methods/serialization.rb +162 -0
  53. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -0
  54. data/lib/active_record/attribute_methods/write.rb +63 -0
  55. data/lib/active_record/attribute_methods.rb +393 -0
  56. data/lib/active_record/autosave_association.rb +426 -0
  57. data/lib/active_record/base.rb +268 -930
  58. data/lib/active_record/callbacks.rb +203 -230
  59. data/lib/active_record/coders/yaml_column.rb +38 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +638 -0
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +390 -0
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +129 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +501 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +873 -0
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +389 -275
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
  71. data/lib/active_record/connection_adapters/column.rb +318 -0
  72. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  73. data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
  74. data/lib/active_record/connection_adapters/mysql_adapter.rb +517 -90
  75. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
  76. data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
  77. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
  79. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
  80. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  81. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
  82. data/lib/active_record/connection_adapters/postgresql_adapter.rb +911 -138
  83. data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
  84. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +624 -0
  85. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  86. data/lib/active_record/connection_handling.rb +98 -0
  87. data/lib/active_record/core.rb +463 -0
  88. data/lib/active_record/counter_cache.rb +122 -0
  89. data/lib/active_record/dynamic_matchers.rb +131 -0
  90. data/lib/active_record/errors.rb +213 -0
  91. data/lib/active_record/explain.rb +38 -0
  92. data/lib/active_record/explain_registry.rb +30 -0
  93. data/lib/active_record/explain_subscriber.rb +29 -0
  94. data/lib/active_record/fixture_set/file.rb +55 -0
  95. data/lib/active_record/fixtures.rb +892 -138
  96. data/lib/active_record/inheritance.rb +200 -0
  97. data/lib/active_record/integration.rb +60 -0
  98. data/lib/active_record/locale/en.yml +47 -0
  99. data/lib/active_record/locking/optimistic.rb +181 -0
  100. data/lib/active_record/locking/pessimistic.rb +77 -0
  101. data/lib/active_record/log_subscriber.rb +82 -0
  102. data/lib/active_record/migration/command_recorder.rb +164 -0
  103. data/lib/active_record/migration/join_table.rb +15 -0
  104. data/lib/active_record/migration.rb +1015 -0
  105. data/lib/active_record/model_schema.rb +345 -0
  106. data/lib/active_record/nested_attributes.rb +546 -0
  107. data/lib/active_record/null_relation.rb +65 -0
  108. data/lib/active_record/persistence.rb +509 -0
  109. data/lib/active_record/query_cache.rb +56 -0
  110. data/lib/active_record/querying.rb +62 -0
  111. data/lib/active_record/railtie.rb +205 -0
  112. data/lib/active_record/railties/console_sandbox.rb +5 -0
  113. data/lib/active_record/railties/controller_runtime.rb +50 -0
  114. data/lib/active_record/railties/databases.rake +402 -0
  115. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  116. data/lib/active_record/readonly_attributes.rb +30 -0
  117. data/lib/active_record/reflection.rb +544 -87
  118. data/lib/active_record/relation/batches.rb +93 -0
  119. data/lib/active_record/relation/calculations.rb +399 -0
  120. data/lib/active_record/relation/delegation.rb +125 -0
  121. data/lib/active_record/relation/finder_methods.rb +349 -0
  122. data/lib/active_record/relation/merger.rb +161 -0
  123. data/lib/active_record/relation/predicate_builder.rb +106 -0
  124. data/lib/active_record/relation/query_methods.rb +1044 -0
  125. data/lib/active_record/relation/spawn_methods.rb +73 -0
  126. data/lib/active_record/relation.rb +655 -0
  127. data/lib/active_record/result.rb +67 -0
  128. data/lib/active_record/runtime_registry.rb +17 -0
  129. data/lib/active_record/sanitization.rb +168 -0
  130. data/lib/active_record/schema.rb +65 -0
  131. data/lib/active_record/schema_dumper.rb +204 -0
  132. data/lib/active_record/schema_migration.rb +39 -0
  133. data/lib/active_record/scoping/default.rb +146 -0
  134. data/lib/active_record/scoping/named.rb +175 -0
  135. data/lib/active_record/scoping.rb +82 -0
  136. data/lib/active_record/serialization.rb +22 -0
  137. data/lib/active_record/serializers/xml_serializer.rb +197 -0
  138. data/lib/active_record/statement_cache.rb +26 -0
  139. data/lib/active_record/store.rb +156 -0
  140. data/lib/active_record/tasks/database_tasks.rb +203 -0
  141. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  142. data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
  143. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  144. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  145. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  146. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  147. data/lib/active_record/test_case.rb +96 -0
  148. data/lib/active_record/timestamp.rb +119 -0
  149. data/lib/active_record/transactions.rb +366 -69
  150. data/lib/active_record/translation.rb +22 -0
  151. data/lib/active_record/validations/associated.rb +49 -0
  152. data/lib/active_record/validations/presence.rb +65 -0
  153. data/lib/active_record/validations/uniqueness.rb +225 -0
  154. data/lib/active_record/validations.rb +64 -185
  155. data/lib/active_record/version.rb +11 -0
  156. data/lib/active_record.rb +149 -24
  157. data/lib/rails/generators/active_record/migration/migration_generator.rb +62 -0
  158. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  159. data/lib/rails/generators/active_record/migration/templates/migration.rb +39 -0
  160. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  161. data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
  162. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  163. data/lib/rails/generators/active_record.rb +23 -0
  164. metadata +261 -161
  165. data/CHANGELOG +0 -581
  166. data/README +0 -361
  167. data/RUNNING_UNIT_TESTS +0 -36
  168. data/dev-utils/eval_debugger.rb +0 -9
  169. data/examples/associations.png +0 -0
  170. data/examples/associations.rb +0 -87
  171. data/examples/shared_setup.rb +0 -15
  172. data/examples/validation.rb +0 -88
  173. data/install.rb +0 -60
  174. data/lib/active_record/associations/association_collection.rb +0 -70
  175. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -107
  176. data/lib/active_record/deprecated_associations.rb +0 -70
  177. data/lib/active_record/observer.rb +0 -71
  178. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  179. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  180. data/lib/active_record/support/clean_logger.rb +0 -10
  181. data/lib/active_record/support/inflector.rb +0 -70
  182. data/lib/active_record/vendor/mysql.rb +0 -1117
  183. data/lib/active_record/vendor/simple.rb +0 -702
  184. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  185. data/lib/active_record/wrappings.rb +0 -59
  186. data/rakefile +0 -122
  187. data/test/abstract_unit.rb +0 -16
  188. data/test/aggregations_test.rb +0 -34
  189. data/test/all.sh +0 -8
  190. data/test/associations_test.rb +0 -477
  191. data/test/base_test.rb +0 -513
  192. data/test/class_inheritable_attributes_test.rb +0 -33
  193. data/test/connections/native_mysql/connection.rb +0 -24
  194. data/test/connections/native_postgresql/connection.rb +0 -24
  195. data/test/connections/native_sqlite/connection.rb +0 -24
  196. data/test/deprecated_associations_test.rb +0 -336
  197. data/test/finder_test.rb +0 -67
  198. data/test/fixtures/accounts/signals37 +0 -3
  199. data/test/fixtures/accounts/unknown +0 -2
  200. data/test/fixtures/auto_id.rb +0 -4
  201. data/test/fixtures/column_name.rb +0 -3
  202. data/test/fixtures/companies/first_client +0 -6
  203. data/test/fixtures/companies/first_firm +0 -4
  204. data/test/fixtures/companies/second_client +0 -6
  205. data/test/fixtures/company.rb +0 -37
  206. data/test/fixtures/company_in_module.rb +0 -33
  207. data/test/fixtures/course.rb +0 -3
  208. data/test/fixtures/courses/java +0 -2
  209. data/test/fixtures/courses/ruby +0 -2
  210. data/test/fixtures/customer.rb +0 -30
  211. data/test/fixtures/customers/david +0 -6
  212. data/test/fixtures/db_definitions/mysql.sql +0 -96
  213. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  214. data/test/fixtures/db_definitions/postgresql.sql +0 -113
  215. data/test/fixtures/db_definitions/postgresql2.sql +0 -4
  216. data/test/fixtures/db_definitions/sqlite.sql +0 -85
  217. data/test/fixtures/db_definitions/sqlite2.sql +0 -4
  218. data/test/fixtures/default.rb +0 -2
  219. data/test/fixtures/developer.rb +0 -8
  220. data/test/fixtures/developers/david +0 -2
  221. data/test/fixtures/developers/jamis +0 -2
  222. data/test/fixtures/developers_projects/david_action_controller +0 -2
  223. data/test/fixtures/developers_projects/david_active_record +0 -2
  224. data/test/fixtures/developers_projects/jamis_active_record +0 -2
  225. data/test/fixtures/entrant.rb +0 -3
  226. data/test/fixtures/entrants/first +0 -3
  227. data/test/fixtures/entrants/second +0 -3
  228. data/test/fixtures/entrants/third +0 -3
  229. data/test/fixtures/fixture_database.sqlite +0 -0
  230. data/test/fixtures/fixture_database_2.sqlite +0 -0
  231. data/test/fixtures/movie.rb +0 -5
  232. data/test/fixtures/movies/first +0 -2
  233. data/test/fixtures/movies/second +0 -2
  234. data/test/fixtures/project.rb +0 -3
  235. data/test/fixtures/projects/action_controller +0 -2
  236. data/test/fixtures/projects/active_record +0 -2
  237. data/test/fixtures/reply.rb +0 -21
  238. data/test/fixtures/subscriber.rb +0 -5
  239. data/test/fixtures/subscribers/first +0 -2
  240. data/test/fixtures/subscribers/second +0 -2
  241. data/test/fixtures/topic.rb +0 -20
  242. data/test/fixtures/topics/first +0 -9
  243. data/test/fixtures/topics/second +0 -8
  244. data/test/fixtures_test.rb +0 -20
  245. data/test/inflector_test.rb +0 -104
  246. data/test/inheritance_test.rb +0 -125
  247. data/test/lifecycle_test.rb +0 -110
  248. data/test/modules_test.rb +0 -21
  249. data/test/multiple_db_test.rb +0 -46
  250. data/test/pk_test.rb +0 -57
  251. data/test/reflection_test.rb +0 -78
  252. data/test/thread_safety_test.rb +0 -33
  253. data/test/transactions_test.rb +0 -83
  254. data/test/unconnected_test.rb +0 -24
  255. data/test/validations_test.rb +0 -126
@@ -0,0 +1,1015 @@
1
+ require "active_support/core_ext/class/attribute_accessors"
2
+ require 'set'
3
+
4
+ module ActiveRecord
5
+ # Exception that can be raised to stop migrations from going backwards.
6
+ class IrreversibleMigration < ActiveRecordError
7
+ end
8
+
9
+ class DuplicateMigrationVersionError < ActiveRecordError#:nodoc:
10
+ def initialize(version)
11
+ super("Multiple migrations have the version number #{version}")
12
+ end
13
+ end
14
+
15
+ class DuplicateMigrationNameError < ActiveRecordError#:nodoc:
16
+ def initialize(name)
17
+ super("Multiple migrations have the name #{name}")
18
+ end
19
+ end
20
+
21
+ class UnknownMigrationVersionError < ActiveRecordError #:nodoc:
22
+ def initialize(version)
23
+ super("No migration with version number #{version}")
24
+ end
25
+ end
26
+
27
+ class IllegalMigrationNameError < ActiveRecordError#:nodoc:
28
+ def initialize(name)
29
+ super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
30
+ end
31
+ end
32
+
33
+ class PendingMigrationError < ActiveRecordError#:nodoc:
34
+ def initialize
35
+ super("Migrations are pending; run 'rake db:migrate RAILS_ENV=#{Rails.env}' to resolve this issue.")
36
+ end
37
+ end
38
+
39
+ # = Active Record Migrations
40
+ #
41
+ # Migrations can manage the evolution of a schema used by several physical
42
+ # databases. It's a solution to the common problem of adding a field to make
43
+ # a new feature work in your local database, but being unsure of how to
44
+ # push that change to other developers and to the production server. With
45
+ # migrations, you can describe the transformations in self-contained classes
46
+ # that can be checked into version control systems and executed against
47
+ # another database that might be one, two, or five versions behind.
48
+ #
49
+ # Example of a simple migration:
50
+ #
51
+ # class AddSsl < ActiveRecord::Migration
52
+ # def up
53
+ # add_column :accounts, :ssl_enabled, :boolean, default: true
54
+ # end
55
+ #
56
+ # def down
57
+ # remove_column :accounts, :ssl_enabled
58
+ # end
59
+ # end
60
+ #
61
+ # This migration will add a boolean flag to the accounts table and remove it
62
+ # if you're backing out of the migration. It shows how all migrations have
63
+ # two methods +up+ and +down+ that describes the transformations
64
+ # required to implement or remove the migration. These methods can consist
65
+ # of both the migration specific methods like +add_column+ and +remove_column+,
66
+ # but may also contain regular Ruby code for generating data needed for the
67
+ # transformations.
68
+ #
69
+ # Example of a more complex migration that also needs to initialize data:
70
+ #
71
+ # class AddSystemSettings < ActiveRecord::Migration
72
+ # def up
73
+ # create_table :system_settings do |t|
74
+ # t.string :name
75
+ # t.string :label
76
+ # t.text :value
77
+ # t.string :type
78
+ # t.integer :position
79
+ # end
80
+ #
81
+ # SystemSetting.create name: 'notice',
82
+ # label: 'Use notice?',
83
+ # value: 1
84
+ # end
85
+ #
86
+ # def down
87
+ # drop_table :system_settings
88
+ # end
89
+ # end
90
+ #
91
+ # This migration first adds the +system_settings+ table, then creates the very
92
+ # first row in it using the Active Record model that relies on the table. It
93
+ # also uses the more advanced +create_table+ syntax where you can specify a
94
+ # complete table schema in one block call.
95
+ #
96
+ # == Available transformations
97
+ #
98
+ # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
99
+ # makes the table object available to a block that can then add columns to it,
100
+ # following the same format as +add_column+. See example above. The options hash
101
+ # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
102
+ # table definition.
103
+ # * <tt>drop_table(name)</tt>: Drops the table called +name+.
104
+ # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
105
+ # the table called +name+. It makes the table object available to a block that
106
+ # can then add/remove columns, indexes or foreign keys to it.
107
+ # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
108
+ # to +new_name+.
109
+ # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
110
+ # to the table called +table_name+
111
+ # named +column_name+ specified to be one of the following types:
112
+ # <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
113
+ # <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
114
+ # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be
115
+ # specified by passing an +options+ hash like <tt>{ default: 11 }</tt>.
116
+ # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
117
+ # <tt>{ limit: 50, null: false }</tt>) -- see
118
+ # ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
119
+ # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
120
+ # a column but keeps the type and content.
121
+ # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
122
+ # the column to a different type using the same parameters as add_column.
123
+ # * <tt>remove_column(table_name, column_names)</tt>: Removes the column listed in
124
+ # +column_names+ from the table called +table_name+.
125
+ # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
126
+ # with the name of the column. Other options include
127
+ # <tt>:name</tt>, <tt>:unique</tt> (e.g.
128
+ # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
129
+ # (e.g. <tt>{ order: { name: :desc } }</tt>).
130
+ # * <tt>remove_index(table_name, column: column_name)</tt>: Removes the index
131
+ # specified by +column_name+.
132
+ # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
133
+ # specified by +index_name+.
134
+ #
135
+ # == Irreversible transformations
136
+ #
137
+ # Some transformations are destructive in a manner that cannot be reversed.
138
+ # Migrations of that kind should raise an <tt>ActiveRecord::IrreversibleMigration</tt>
139
+ # exception in their +down+ method.
140
+ #
141
+ # == Running migrations from within Rails
142
+ #
143
+ # The Rails package has several tools to help create and apply migrations.
144
+ #
145
+ # To generate a new migration, you can use
146
+ # rails generate migration MyNewMigration
147
+ #
148
+ # where MyNewMigration is the name of your migration. The generator will
149
+ # create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
150
+ # in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
151
+ # UTC formatted date and time that the migration was generated.
152
+ #
153
+ # You may then edit the <tt>up</tt> and <tt>down</tt> methods of
154
+ # MyNewMigration.
155
+ #
156
+ # There is a special syntactic shortcut to generate migrations that add fields to a table.
157
+ #
158
+ # rails generate migration add_fieldname_to_tablename fieldname:string
159
+ #
160
+ # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
161
+ # class AddFieldnameToTablename < ActiveRecord::Migration
162
+ # def up
163
+ # add_column :tablenames, :fieldname, :string
164
+ # end
165
+ #
166
+ # def down
167
+ # remove_column :tablenames, :fieldname
168
+ # end
169
+ # end
170
+ #
171
+ # To run migrations against the currently configured database, use
172
+ # <tt>rake db:migrate</tt>. This will update the database by running all of the
173
+ # pending migrations, creating the <tt>schema_migrations</tt> table
174
+ # (see "About the schema_migrations table" section below) if missing. It will also
175
+ # invoke the db:schema:dump task, which will update your db/schema.rb file
176
+ # to match the structure of your database.
177
+ #
178
+ # To roll the database back to a previous migration version, use
179
+ # <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
180
+ # you wish to downgrade. If any of the migrations throw an
181
+ # <tt>ActiveRecord::IrreversibleMigration</tt> exception, that step will fail and you'll
182
+ # have some manual work to do.
183
+ #
184
+ # == Database support
185
+ #
186
+ # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
187
+ # SQL Server, Sybase, and Oracle (all supported databases except DB2).
188
+ #
189
+ # == More examples
190
+ #
191
+ # Not all migrations change the schema. Some just fix the data:
192
+ #
193
+ # class RemoveEmptyTags < ActiveRecord::Migration
194
+ # def up
195
+ # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
196
+ # end
197
+ #
198
+ # def down
199
+ # # not much we can do to restore deleted data
200
+ # raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
201
+ # end
202
+ # end
203
+ #
204
+ # Others remove columns when they migrate up instead of down:
205
+ #
206
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
207
+ # def up
208
+ # remove_column :items, :incomplete_items_count
209
+ # remove_column :items, :completed_items_count
210
+ # end
211
+ #
212
+ # def down
213
+ # add_column :items, :incomplete_items_count
214
+ # add_column :items, :completed_items_count
215
+ # end
216
+ # end
217
+ #
218
+ # And sometimes you need to do something in SQL not abstracted directly by migrations:
219
+ #
220
+ # class MakeJoinUnique < ActiveRecord::Migration
221
+ # def up
222
+ # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
223
+ # end
224
+ #
225
+ # def down
226
+ # execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
227
+ # end
228
+ # end
229
+ #
230
+ # == Using a model after changing its table
231
+ #
232
+ # Sometimes you'll want to add a column in a migration and populate it
233
+ # immediately after. In that case, you'll need to make a call to
234
+ # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
235
+ # latest column data from after the new column was added. Example:
236
+ #
237
+ # class AddPeopleSalary < ActiveRecord::Migration
238
+ # def up
239
+ # add_column :people, :salary, :integer
240
+ # Person.reset_column_information
241
+ # Person.all.each do |p|
242
+ # p.update_attribute :salary, SalaryCalculator.compute(p)
243
+ # end
244
+ # end
245
+ # end
246
+ #
247
+ # == Controlling verbosity
248
+ #
249
+ # By default, migrations will describe the actions they are taking, writing
250
+ # them to the console as they happen, along with benchmarks describing how
251
+ # long each step took.
252
+ #
253
+ # You can quiet them down by setting ActiveRecord::Migration.verbose = false.
254
+ #
255
+ # You can also insert your own messages and benchmarks by using the +say_with_time+
256
+ # method:
257
+ #
258
+ # def up
259
+ # ...
260
+ # say_with_time "Updating salaries..." do
261
+ # Person.all.each do |p|
262
+ # p.update_attribute :salary, SalaryCalculator.compute(p)
263
+ # end
264
+ # end
265
+ # ...
266
+ # end
267
+ #
268
+ # The phrase "Updating salaries..." would then be printed, along with the
269
+ # benchmark for the block when the block completes.
270
+ #
271
+ # == About the schema_migrations table
272
+ #
273
+ # Rails versions 2.0 and prior used to create a table called
274
+ # <tt>schema_info</tt> when using migrations. This table contained the
275
+ # version of the schema as of the last applied migration.
276
+ #
277
+ # Starting with Rails 2.1, the <tt>schema_info</tt> table is
278
+ # (automatically) replaced by the <tt>schema_migrations</tt> table, which
279
+ # contains the version numbers of all the migrations applied.
280
+ #
281
+ # As a result, it is now possible to add migration files that are numbered
282
+ # lower than the current schema version: when migrating up, those
283
+ # never-applied "interleaved" migrations will be automatically applied, and
284
+ # when migrating down, never-applied "interleaved" migrations will be skipped.
285
+ #
286
+ # == Timestamped Migrations
287
+ #
288
+ # By default, Rails generates migrations that look like:
289
+ #
290
+ # 20080717013526_your_migration_name.rb
291
+ #
292
+ # The prefix is a generation timestamp (in UTC).
293
+ #
294
+ # If you'd prefer to use numeric prefixes, you can turn timestamped migrations
295
+ # off by setting:
296
+ #
297
+ # config.active_record.timestamped_migrations = false
298
+ #
299
+ # In application.rb.
300
+ #
301
+ # == Reversible Migrations
302
+ #
303
+ # Starting with Rails 3.1, you will be able to define reversible migrations.
304
+ # Reversible migrations are migrations that know how to go +down+ for you.
305
+ # You simply supply the +up+ logic, and the Migration system will figure out
306
+ # how to execute the down commands for you.
307
+ #
308
+ # To define a reversible migration, define the +change+ method in your
309
+ # migration like this:
310
+ #
311
+ # class TenderloveMigration < ActiveRecord::Migration
312
+ # def change
313
+ # create_table(:horses) do |t|
314
+ # t.column :content, :text
315
+ # t.column :remind_at, :datetime
316
+ # end
317
+ # end
318
+ # end
319
+ #
320
+ # This migration will create the horses table for you on the way up, and
321
+ # automatically figure out how to drop the table on the way down.
322
+ #
323
+ # Some commands like +remove_column+ cannot be reversed. If you care to
324
+ # define how to move up and down in these cases, you should define the +up+
325
+ # and +down+ methods as before.
326
+ #
327
+ # If a command cannot be reversed, an
328
+ # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
329
+ # the migration is moving down.
330
+ #
331
+ # For a list of commands that are reversible, please see
332
+ # <tt>ActiveRecord::Migration::CommandRecorder</tt>.
333
+ #
334
+ # == Transactional Migrations
335
+ #
336
+ # If the database adapter supports DDL transactions, all migrations will
337
+ # automatically be wrapped in a transaction. There are queries that you
338
+ # can't execute inside a transaction though, and for these situations
339
+ # you can turn the automatic transactions off.
340
+ #
341
+ # class ChangeEnum < ActiveRecord::Migration
342
+ # disable_ddl_transaction!
343
+ #
344
+ # def up
345
+ # execute "ALTER TYPE model_size ADD VALUE 'new_value'"
346
+ # end
347
+ # end
348
+ #
349
+ # Remember that you can still open your own transactions, even if you
350
+ # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
351
+ class Migration
352
+ autoload :CommandRecorder, 'active_record/migration/command_recorder'
353
+
354
+
355
+ # This class is used to verify that all migrations have been run before
356
+ # loading a web page if config.active_record.migration_error is set to :page_load
357
+ class CheckPending
358
+ def initialize(app)
359
+ @app = app
360
+ @last_check = 0
361
+ end
362
+
363
+ def call(env)
364
+ mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
365
+ if @last_check < mtime
366
+ ActiveRecord::Migration.check_pending!
367
+ @last_check = mtime
368
+ end
369
+ @app.call(env)
370
+ end
371
+ end
372
+
373
+ class << self
374
+ attr_accessor :delegate # :nodoc:
375
+ attr_accessor :disable_ddl_transaction # :nodoc:
376
+ end
377
+
378
+ def self.check_pending!
379
+ raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?
380
+ end
381
+
382
+ def self.method_missing(name, *args, &block) # :nodoc:
383
+ (delegate || superclass.delegate).send(name, *args, &block)
384
+ end
385
+
386
+ def self.migrate(direction)
387
+ new.migrate direction
388
+ end
389
+
390
+ # Disable DDL transactions for this migration.
391
+ def self.disable_ddl_transaction!
392
+ @disable_ddl_transaction = true
393
+ end
394
+
395
+ def disable_ddl_transaction # :nodoc:
396
+ self.class.disable_ddl_transaction
397
+ end
398
+
399
+ cattr_accessor :verbose
400
+ attr_accessor :name, :version
401
+
402
+ def initialize(name = self.class.name, version = nil)
403
+ @name = name
404
+ @version = version
405
+ @connection = nil
406
+ end
407
+
408
+ self.verbose = true
409
+ # instantiate the delegate object after initialize is defined
410
+ self.delegate = new
411
+
412
+ # Reverses the migration commands for the given block and
413
+ # the given migrations.
414
+ #
415
+ # The following migration will remove the table 'horses'
416
+ # and create the table 'apples' on the way up, and the reverse
417
+ # on the way down.
418
+ #
419
+ # class FixTLMigration < ActiveRecord::Migration
420
+ # def change
421
+ # revert do
422
+ # create_table(:horses) do |t|
423
+ # t.text :content
424
+ # t.datetime :remind_at
425
+ # end
426
+ # end
427
+ # create_table(:apples) do |t|
428
+ # t.string :variety
429
+ # end
430
+ # end
431
+ # end
432
+ #
433
+ # Or equivalently, if +TenderloveMigration+ is defined as in the
434
+ # documentation for Migration:
435
+ #
436
+ # require_relative '2012121212_tenderlove_migration'
437
+ #
438
+ # class FixupTLMigration < ActiveRecord::Migration
439
+ # def change
440
+ # revert TenderloveMigration
441
+ #
442
+ # create_table(:apples) do |t|
443
+ # t.string :variety
444
+ # end
445
+ # end
446
+ # end
447
+ #
448
+ # This command can be nested.
449
+ def revert(*migration_classes)
450
+ run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
451
+ if block_given?
452
+ if @connection.respond_to? :revert
453
+ @connection.revert { yield }
454
+ else
455
+ recorder = CommandRecorder.new(@connection)
456
+ @connection = recorder
457
+ suppress_messages do
458
+ @connection.revert { yield }
459
+ end
460
+ @connection = recorder.delegate
461
+ recorder.commands.each do |cmd, args, block|
462
+ send(cmd, *args, &block)
463
+ end
464
+ end
465
+ end
466
+ end
467
+
468
+ def reverting?
469
+ @connection.respond_to?(:reverting) && @connection.reverting
470
+ end
471
+
472
+ class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
473
+ def up
474
+ yield unless reverting
475
+ end
476
+
477
+ def down
478
+ yield if reverting
479
+ end
480
+ end
481
+
482
+ # Used to specify an operation that can be run in one direction or another.
483
+ # Call the methods +up+ and +down+ of the yielded object to run a block
484
+ # only in one given direction.
485
+ # The whole block will be called in the right order within the migration.
486
+ #
487
+ # In the following example, the looping on users will always be done
488
+ # when the three columns 'first_name', 'last_name' and 'full_name' exist,
489
+ # even when migrating down:
490
+ #
491
+ # class SplitNameMigration < ActiveRecord::Migration
492
+ # def change
493
+ # add_column :users, :first_name, :string
494
+ # add_column :users, :last_name, :string
495
+ #
496
+ # reversible do |dir|
497
+ # User.reset_column_information
498
+ # User.all.each do |u|
499
+ # dir.up { u.first_name, u.last_name = u.full_name.split(' ') }
500
+ # dir.down { u.full_name = "#{u.first_name} #{u.last_name}" }
501
+ # u.save
502
+ # end
503
+ # end
504
+ #
505
+ # revert { add_column :users, :full_name, :string }
506
+ # end
507
+ # end
508
+ def reversible
509
+ helper = ReversibleBlockHelper.new(reverting?)
510
+ execute_block{ yield helper }
511
+ end
512
+
513
+ # Runs the given migration classes.
514
+ # Last argument can specify options:
515
+ # - :direction (default is :up)
516
+ # - :revert (default is false)
517
+ def run(*migration_classes)
518
+ opts = migration_classes.extract_options!
519
+ dir = opts[:direction] || :up
520
+ dir = (dir == :down ? :up : :down) if opts[:revert]
521
+ if reverting?
522
+ # If in revert and going :up, say, we want to execute :down without reverting, so
523
+ revert { run(*migration_classes, direction: dir, revert: true) }
524
+ else
525
+ migration_classes.each do |migration_class|
526
+ migration_class.new.exec_migration(@connection, dir)
527
+ end
528
+ end
529
+ end
530
+
531
+ def up
532
+ self.class.delegate = self
533
+ return unless self.class.respond_to?(:up)
534
+ self.class.up
535
+ end
536
+
537
+ def down
538
+ self.class.delegate = self
539
+ return unless self.class.respond_to?(:down)
540
+ self.class.down
541
+ end
542
+
543
+ # Execute this migration in the named direction
544
+ def migrate(direction)
545
+ return unless respond_to?(direction)
546
+
547
+ case direction
548
+ when :up then announce "migrating"
549
+ when :down then announce "reverting"
550
+ end
551
+
552
+ time = nil
553
+ ActiveRecord::Base.connection_pool.with_connection do |conn|
554
+ time = Benchmark.measure do
555
+ exec_migration(conn, direction)
556
+ end
557
+ end
558
+
559
+ case direction
560
+ when :up then announce "migrated (%.4fs)" % time.real; write
561
+ when :down then announce "reverted (%.4fs)" % time.real; write
562
+ end
563
+ end
564
+
565
+ def exec_migration(conn, direction)
566
+ @connection = conn
567
+ if respond_to?(:change)
568
+ if direction == :down
569
+ revert { change }
570
+ else
571
+ change
572
+ end
573
+ else
574
+ send(direction)
575
+ end
576
+ ensure
577
+ @connection = nil
578
+ end
579
+
580
+ def write(text="")
581
+ puts(text) if verbose
582
+ end
583
+
584
+ def announce(message)
585
+ text = "#{version} #{name}: #{message}"
586
+ length = [0, 75 - text.length].max
587
+ write "== %s %s" % [text, "=" * length]
588
+ end
589
+
590
+ def say(message, subitem=false)
591
+ write "#{subitem ? " ->" : "--"} #{message}"
592
+ end
593
+
594
+ def say_with_time(message)
595
+ say(message)
596
+ result = nil
597
+ time = Benchmark.measure { result = yield }
598
+ say "%.4fs" % time.real, :subitem
599
+ say("#{result} rows", :subitem) if result.is_a?(Integer)
600
+ result
601
+ end
602
+
603
+ def suppress_messages
604
+ save, self.verbose = verbose, false
605
+ yield
606
+ ensure
607
+ self.verbose = save
608
+ end
609
+
610
+ def connection
611
+ @connection || ActiveRecord::Base.connection
612
+ end
613
+
614
+ def method_missing(method, *arguments, &block)
615
+ arg_list = arguments.map{ |a| a.inspect } * ', '
616
+
617
+ say_with_time "#{method}(#{arg_list})" do
618
+ unless @connection.respond_to? :revert
619
+ unless arguments.empty? || method == :execute
620
+ arguments[0] = Migrator.proper_table_name(arguments.first)
621
+ arguments[1] = Migrator.proper_table_name(arguments.second) if method == :rename_table
622
+ end
623
+ end
624
+ return super unless connection.respond_to?(method)
625
+ connection.send(method, *arguments, &block)
626
+ end
627
+ end
628
+
629
+ def copy(destination, sources, options = {})
630
+ copied = []
631
+
632
+ FileUtils.mkdir_p(destination) unless File.exists?(destination)
633
+
634
+ destination_migrations = ActiveRecord::Migrator.migrations(destination)
635
+ last = destination_migrations.last
636
+ sources.each do |scope, path|
637
+ source_migrations = ActiveRecord::Migrator.migrations(path)
638
+
639
+ source_migrations.each do |migration|
640
+ source = File.binread(migration.filename)
641
+ inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
642
+ if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
643
+ # If we have a magic comment in the original migration,
644
+ # insert our comment after the first newline(end of the magic comment line)
645
+ # so the magic keep working.
646
+ # Note that magic comments must be at the first line(except sh-bang).
647
+ source[/\n/] = "\n#{inserted_comment}"
648
+ else
649
+ source = "#{inserted_comment}#{source}"
650
+ end
651
+
652
+ if duplicate = destination_migrations.detect { |m| m.name == migration.name }
653
+ if options[:on_skip] && duplicate.scope != scope.to_s
654
+ options[:on_skip].call(scope, migration)
655
+ end
656
+ next
657
+ end
658
+
659
+ migration.version = next_migration_number(last ? last.version + 1 : 0).to_i
660
+ new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.#{scope}.rb")
661
+ old_path, migration.filename = migration.filename, new_path
662
+ last = migration
663
+
664
+ File.binwrite(migration.filename, source)
665
+ copied << migration
666
+ options[:on_copy].call(scope, migration, old_path) if options[:on_copy]
667
+ destination_migrations << migration
668
+ end
669
+ end
670
+
671
+ copied
672
+ end
673
+
674
+ def next_migration_number(number)
675
+ if ActiveRecord::Base.timestamped_migrations
676
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
677
+ else
678
+ "%.3d" % number
679
+ end
680
+ end
681
+
682
+ private
683
+ def execute_block
684
+ if connection.respond_to? :execute_block
685
+ super # use normal delegation to record the block
686
+ else
687
+ yield
688
+ end
689
+ end
690
+ end
691
+
692
+ # MigrationProxy is used to defer loading of the actual migration classes
693
+ # until they are needed
694
+ class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
695
+
696
+ def initialize(name, version, filename, scope)
697
+ super
698
+ @migration = nil
699
+ end
700
+
701
+ def basename
702
+ File.basename(filename)
703
+ end
704
+
705
+ def mtime
706
+ File.mtime filename
707
+ end
708
+
709
+ delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
710
+
711
+ private
712
+
713
+ def migration
714
+ @migration ||= load_migration
715
+ end
716
+
717
+ def load_migration
718
+ require(File.expand_path(filename))
719
+ name.constantize.new
720
+ end
721
+
722
+ end
723
+
724
+ class NullMigration < MigrationProxy #:nodoc:
725
+ def initialize
726
+ super(nil, 0, nil, nil)
727
+ end
728
+
729
+ def mtime
730
+ 0
731
+ end
732
+ end
733
+
734
+ class Migrator#:nodoc:
735
+ class << self
736
+ attr_writer :migrations_paths
737
+ alias :migrations_path= :migrations_paths=
738
+
739
+ def migrate(migrations_paths, target_version = nil, &block)
740
+ case
741
+ when target_version.nil?
742
+ up(migrations_paths, target_version, &block)
743
+ when current_version == 0 && target_version == 0
744
+ []
745
+ when current_version > target_version
746
+ down(migrations_paths, target_version, &block)
747
+ else
748
+ up(migrations_paths, target_version, &block)
749
+ end
750
+ end
751
+
752
+ def rollback(migrations_paths, steps=1)
753
+ move(:down, migrations_paths, steps)
754
+ end
755
+
756
+ def forward(migrations_paths, steps=1)
757
+ move(:up, migrations_paths, steps)
758
+ end
759
+
760
+ def up(migrations_paths, target_version = nil)
761
+ migrations = migrations(migrations_paths)
762
+ migrations.select! { |m| yield m } if block_given?
763
+
764
+ self.new(:up, migrations, target_version).migrate
765
+ end
766
+
767
+ def down(migrations_paths, target_version = nil, &block)
768
+ migrations = migrations(migrations_paths)
769
+ migrations.select! { |m| yield m } if block_given?
770
+
771
+ self.new(:down, migrations, target_version).migrate
772
+ end
773
+
774
+ def run(direction, migrations_paths, target_version)
775
+ self.new(direction, migrations(migrations_paths), target_version).run
776
+ end
777
+
778
+ def open(migrations_paths)
779
+ self.new(:up, migrations(migrations_paths), nil)
780
+ end
781
+
782
+ def schema_migrations_table_name
783
+ SchemaMigration.table_name
784
+ end
785
+
786
+ def get_all_versions
787
+ SchemaMigration.all.map { |x| x.version.to_i }.sort
788
+ end
789
+
790
+ def current_version
791
+ sm_table = schema_migrations_table_name
792
+ if Base.connection.table_exists?(sm_table)
793
+ get_all_versions.max || 0
794
+ else
795
+ 0
796
+ end
797
+ end
798
+
799
+ def needs_migration?
800
+ current_version < last_version
801
+ end
802
+
803
+ def last_version
804
+ last_migration.version
805
+ end
806
+
807
+ def last_migration #:nodoc:
808
+ migrations(migrations_paths).last || NullMigration.new
809
+ end
810
+
811
+ def proper_table_name(name)
812
+ # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
813
+ if name.respond_to? :table_name
814
+ name.table_name
815
+ else
816
+ "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
817
+ end
818
+ end
819
+
820
+ def migrations_paths
821
+ @migrations_paths ||= ['db/migrate']
822
+ # just to not break things if someone uses: migration_path = some_string
823
+ Array(@migrations_paths)
824
+ end
825
+
826
+ def migrations_path
827
+ migrations_paths.first
828
+ end
829
+
830
+ def migrations(paths)
831
+ paths = Array(paths)
832
+
833
+ files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
834
+
835
+ migrations = files.map do |file|
836
+ version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
837
+
838
+ raise IllegalMigrationNameError.new(file) unless version
839
+ version = version.to_i
840
+ name = name.camelize
841
+
842
+ MigrationProxy.new(name, version, file, scope)
843
+ end
844
+
845
+ migrations.sort_by(&:version)
846
+ end
847
+
848
+ private
849
+
850
+ def move(direction, migrations_paths, steps)
851
+ migrator = self.new(direction, migrations(migrations_paths))
852
+ start_index = migrator.migrations.index(migrator.current_migration)
853
+
854
+ if start_index
855
+ finish = migrator.migrations[start_index + steps]
856
+ version = finish ? finish.version : 0
857
+ send(direction, migrations_paths, version)
858
+ end
859
+ end
860
+ end
861
+
862
+ def initialize(direction, migrations, target_version = nil)
863
+ raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
864
+
865
+ @direction = direction
866
+ @target_version = target_version
867
+ @migrated_versions = nil
868
+
869
+ if Array(migrations).grep(String).empty?
870
+ @migrations = migrations
871
+ else
872
+ ActiveSupport::Deprecation.warn "instantiate this class with a list of migrations"
873
+ @migrations = self.class.migrations(migrations)
874
+ end
875
+
876
+ validate(@migrations)
877
+
878
+ ActiveRecord::SchemaMigration.create_table
879
+ end
880
+
881
+ def current_version
882
+ migrated.max || 0
883
+ end
884
+
885
+ def current_migration
886
+ migrations.detect { |m| m.version == current_version }
887
+ end
888
+ alias :current :current_migration
889
+
890
+ def run
891
+ migration = migrations.detect { |m| m.version == @target_version }
892
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
893
+ unless (up? && migrated.include?(migration.version.to_i)) || (down? && !migrated.include?(migration.version.to_i))
894
+ begin
895
+ execute_migration_in_transaction(migration, @direction)
896
+ rescue => e
897
+ canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
898
+ raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
899
+ end
900
+ end
901
+ end
902
+
903
+ def migrate
904
+ if !target && @target_version && @target_version > 0
905
+ raise UnknownMigrationVersionError.new(@target_version)
906
+ end
907
+
908
+ running = runnable
909
+
910
+ if block_given?
911
+ message = "block argument to migrate is deprecated, please filter migrations before constructing the migrator"
912
+ ActiveSupport::Deprecation.warn message
913
+ running.select! { |m| yield m }
914
+ end
915
+
916
+ running.each do |migration|
917
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
918
+
919
+ begin
920
+ execute_migration_in_transaction(migration, @direction)
921
+ rescue => e
922
+ canceled_msg = use_transaction?(migration) ? "this and " : ""
923
+ raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
924
+ end
925
+ end
926
+ end
927
+
928
+ def runnable
929
+ runnable = migrations[start..finish]
930
+ if up?
931
+ runnable.reject { |m| ran?(m) }
932
+ else
933
+ # skip the last migration if we're headed down, but not ALL the way down
934
+ runnable.pop if target
935
+ runnable.find_all { |m| ran?(m) }
936
+ end
937
+ end
938
+
939
+ def migrations
940
+ down? ? @migrations.reverse : @migrations.sort_by(&:version)
941
+ end
942
+
943
+ def pending_migrations
944
+ already_migrated = migrated
945
+ migrations.reject { |m| already_migrated.include?(m.version) }
946
+ end
947
+
948
+ def migrated
949
+ @migrated_versions ||= Set.new(self.class.get_all_versions)
950
+ end
951
+
952
+ private
953
+ def ran?(migration)
954
+ migrated.include?(migration.version.to_i)
955
+ end
956
+
957
+ def execute_migration_in_transaction(migration, direction)
958
+ ddl_transaction(migration) do
959
+ migration.migrate(direction)
960
+ record_version_state_after_migrating(migration.version)
961
+ end
962
+ end
963
+
964
+ def target
965
+ migrations.detect { |m| m.version == @target_version }
966
+ end
967
+
968
+ def finish
969
+ migrations.index(target) || migrations.size - 1
970
+ end
971
+
972
+ def start
973
+ up? ? 0 : (migrations.index(current) || 0)
974
+ end
975
+
976
+ def validate(migrations)
977
+ name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
978
+ raise DuplicateMigrationNameError.new(name) if name
979
+
980
+ version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
981
+ raise DuplicateMigrationVersionError.new(version) if version
982
+ end
983
+
984
+ def record_version_state_after_migrating(version)
985
+ if down?
986
+ migrated.delete(version)
987
+ ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
988
+ else
989
+ migrated << version
990
+ ActiveRecord::SchemaMigration.create!(:version => version.to_s)
991
+ end
992
+ end
993
+
994
+ def up?
995
+ @direction == :up
996
+ end
997
+
998
+ def down?
999
+ @direction == :down
1000
+ end
1001
+
1002
+ # Wrap the migration in a transaction only if supported by the adapter.
1003
+ def ddl_transaction(migration)
1004
+ if use_transaction?(migration)
1005
+ Base.transaction { yield }
1006
+ else
1007
+ yield
1008
+ end
1009
+ end
1010
+
1011
+ def use_transaction?(migration)
1012
+ !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1013
+ end
1014
+ end
1015
+ end