activerecord 3.2.22.5 → 4.2.11.3

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 (236) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1632 -609
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +37 -41
  5. data/examples/performance.rb +31 -19
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +56 -42
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -36
  10. data/lib/active_record/associations/association.rb +73 -55
  11. data/lib/active_record/associations/association_scope.rb +143 -82
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +125 -31
  15. data/lib/active_record/associations/builder/belongs_to.rb +89 -61
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +23 -17
  21. data/lib/active_record/associations/collection_association.rb +251 -177
  22. data/lib/active_record/associations/collection_proxy.rb +963 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +113 -22
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -39
  26. data/lib/active_record/associations/has_one_association.rb +43 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -107
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +62 -33
  38. data/lib/active_record/associations/preloader.rb +101 -79
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +30 -16
  41. data/lib/active_record/associations.rb +463 -345
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +142 -151
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +137 -57
  47. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +73 -106
  50. data/lib/active_record/attribute_methods/serialization.rb +44 -94
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
  52. data/lib/active_record/attribute_methods/write.rb +57 -44
  53. data/lib/active_record/attribute_methods.rb +301 -141
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +246 -217
  58. data/lib/active_record/base.rb +70 -474
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +396 -219
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +261 -169
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
  75. data/lib/active_record/connection_adapters/column.rb +31 -245
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +430 -999
  114. data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +157 -105
  119. data/lib/active_record/dynamic_matchers.rb +119 -63
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +94 -36
  122. data/lib/active_record/explain.rb +15 -63
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +9 -5
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +302 -215
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +143 -70
  129. data/lib/active_record/integration.rb +65 -12
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +73 -52
  133. data/lib/active_record/locking/pessimistic.rb +5 -5
  134. data/lib/active_record/log_subscriber.rb +24 -21
  135. data/lib/active_record/migration/command_recorder.rb +124 -32
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +511 -213
  138. data/lib/active_record/model_schema.rb +91 -117
  139. data/lib/active_record/nested_attributes.rb +184 -130
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +276 -117
  143. data/lib/active_record/query_cache.rb +19 -37
  144. data/lib/active_record/querying.rb +28 -18
  145. data/lib/active_record/railtie.rb +73 -40
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +4 -3
  148. data/lib/active_record/railties/databases.rake +141 -416
  149. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  150. data/lib/active_record/readonly_attributes.rb +1 -4
  151. data/lib/active_record/reflection.rb +513 -154
  152. data/lib/active_record/relation/batches.rb +91 -43
  153. data/lib/active_record/relation/calculations.rb +199 -161
  154. data/lib/active_record/relation/delegation.rb +116 -25
  155. data/lib/active_record/relation/finder_methods.rb +362 -248
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -43
  160. data/lib/active_record/relation/query_methods.rb +928 -167
  161. data/lib/active_record/relation/spawn_methods.rb +48 -149
  162. data/lib/active_record/relation.rb +352 -207
  163. data/lib/active_record/result.rb +101 -10
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +56 -59
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +106 -63
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +50 -57
  170. data/lib/active_record/scoping/named.rb +73 -109
  171. data/lib/active_record/scoping.rb +58 -123
  172. data/lib/active_record/serialization.rb +6 -2
  173. data/lib/active_record/serializers/xml_serializer.rb +12 -22
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +168 -15
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +23 -16
  181. data/lib/active_record/transactions.rb +125 -79
  182. data/lib/active_record/type/big_integer.rb +13 -0
  183. data/lib/active_record/type/binary.rb +50 -0
  184. data/lib/active_record/type/boolean.rb +31 -0
  185. data/lib/active_record/type/date.rb +50 -0
  186. data/lib/active_record/type/date_time.rb +54 -0
  187. data/lib/active_record/type/decimal.rb +64 -0
  188. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  189. data/lib/active_record/type/decorator.rb +14 -0
  190. data/lib/active_record/type/float.rb +19 -0
  191. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  192. data/lib/active_record/type/integer.rb +59 -0
  193. data/lib/active_record/type/mutable.rb +16 -0
  194. data/lib/active_record/type/numeric.rb +36 -0
  195. data/lib/active_record/type/serialized.rb +62 -0
  196. data/lib/active_record/type/string.rb +40 -0
  197. data/lib/active_record/type/text.rb +11 -0
  198. data/lib/active_record/type/time.rb +26 -0
  199. data/lib/active_record/type/time_value.rb +38 -0
  200. data/lib/active_record/type/type_map.rb +64 -0
  201. data/lib/active_record/type/unsigned_integer.rb +15 -0
  202. data/lib/active_record/type/value.rb +110 -0
  203. data/lib/active_record/type.rb +23 -0
  204. data/lib/active_record/validations/associated.rb +24 -16
  205. data/lib/active_record/validations/presence.rb +67 -0
  206. data/lib/active_record/validations/uniqueness.rb +123 -64
  207. data/lib/active_record/validations.rb +36 -29
  208. data/lib/active_record/version.rb +5 -7
  209. data/lib/active_record.rb +66 -46
  210. data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
  211. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
  212. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  213. data/lib/rails/generators/active_record/migration.rb +11 -8
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
  215. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  216. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  217. data/lib/rails/generators/active_record.rb +3 -11
  218. metadata +101 -45
  219. data/examples/associations.png +0 -0
  220. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  221. data/lib/active_record/associations/join_helper.rb +0 -55
  222. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  223. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  226. data/lib/active_record/dynamic_finder_match.rb +0 -68
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/fixtures/file.rb +0 -65
  229. data/lib/active_record/identity_map.rb +0 -162
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -360
  232. data/lib/active_record/test_case.rb +0 -73
  233. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  234. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  235. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  236. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -3,12 +3,12 @@ module ActiveRecord
3
3
  # Locking::Pessimistic provides support for row-level locking using
4
4
  # SELECT ... FOR UPDATE and other lock types.
5
5
  #
6
- # Pass <tt>:lock => true</tt> to <tt>ActiveRecord::Base.find</tt> to obtain an exclusive
6
+ # Chain <tt>ActiveRecord::Base#find</tt> to <tt>ActiveRecord::QueryMethods#lock</tt> to obtain an exclusive
7
7
  # lock on the selected rows:
8
8
  # # select * from accounts where id=1 for update
9
- # Account.find(1, :lock => true)
9
+ # Account.lock.find(1)
10
10
  #
11
- # Pass <tt>:lock => 'some locking clause'</tt> to give a database-specific locking clause
11
+ # Call <tt>lock('some locking clause')</tt> to use a database-specific locking clause
12
12
  # of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'. Example:
13
13
  #
14
14
  # Account.transaction do
@@ -26,7 +26,7 @@ module ActiveRecord
26
26
  #
27
27
  # Account.transaction do
28
28
  # # select * from accounts where ...
29
- # accounts = Account.where(...).all
29
+ # accounts = Account.where(...)
30
30
  # account1 = accounts.detect { |account| ... }
31
31
  # account2 = accounts.detect { |account| ... }
32
32
  # # select * from accounts where id=? for update
@@ -64,7 +64,7 @@ module ActiveRecord
64
64
  end
65
65
 
66
66
  # Wraps the passed block in a transaction, locking the object
67
- # before yielding. You pass can the SQL locking clause
67
+ # before yielding. You can pass the SQL locking clause
68
68
  # as argument (see <tt>lock!</tt>).
69
69
  def with_lock(lock = true)
70
70
  transaction do
@@ -1,11 +1,13 @@
1
1
  module ActiveRecord
2
2
  class LogSubscriber < ActiveSupport::LogSubscriber
3
+ IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
4
+
3
5
  def self.runtime=(value)
4
- Thread.current["active_record_sql_runtime"] = value
6
+ ActiveRecord::RuntimeRegistry.sql_runtime = value
5
7
  end
6
8
 
7
9
  def self.runtime
8
- Thread.current["active_record_sql_runtime"] ||= 0
10
+ ActiveRecord::RuntimeRegistry.sql_runtime ||= 0
9
11
  end
10
12
 
11
13
  def self.reset_runtime
@@ -15,7 +17,21 @@ module ActiveRecord
15
17
 
16
18
  def initialize
17
19
  super
18
- @odd_or_even = false
20
+ @odd = false
21
+ end
22
+
23
+ def render_bind(column, value)
24
+ if column
25
+ if column.binary?
26
+ # This specifically deals with the PG adapter that casts bytea columns into a Hash.
27
+ value = value[:value] if value.is_a?(Hash)
28
+ value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
29
+ end
30
+
31
+ [column.name, value]
32
+ else
33
+ [nil, value]
34
+ end
19
35
  end
20
36
 
21
37
  def sql(event)
@@ -24,19 +40,15 @@ module ActiveRecord
24
40
 
25
41
  payload = event.payload
26
42
 
27
- return if 'SCHEMA' == payload[:name]
43
+ return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
28
44
 
29
- name = '%s (%.1fms)' % [payload[:name], event.duration]
30
- sql = payload[:sql].squeeze(' ')
45
+ name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
46
+ sql = payload[:sql]
31
47
  binds = nil
32
48
 
33
49
  unless (payload[:binds] || []).empty?
34
50
  binds = " " + payload[:binds].map { |col,v|
35
- if col
36
- [col.name, v]
37
- else
38
- [nil, v]
39
- end
51
+ render_bind(col, v)
40
52
  }.inspect
41
53
  end
42
54
 
@@ -50,17 +62,8 @@ module ActiveRecord
50
62
  debug " #{name} #{sql}#{binds}"
51
63
  end
52
64
 
53
- def identity(event)
54
- return unless logger.debug?
55
-
56
- name = color(event.payload[:name], odd? ? CYAN : MAGENTA, true)
57
- line = odd? ? color(event.payload[:line], nil, true) : event.payload[:line]
58
-
59
- debug " #{name} #{line}"
60
- end
61
-
62
65
  def odd?
63
- @odd_or_even = !@odd_or_even
66
+ @odd = !@odd
64
67
  end
65
68
 
66
69
  def logger
@@ -8,66 +8,128 @@ module ActiveRecord
8
8
  # * add_index
9
9
  # * add_timestamps
10
10
  # * create_table
11
+ # * create_join_table
11
12
  # * remove_timestamps
12
13
  # * rename_column
13
14
  # * rename_index
14
15
  # * rename_table
15
16
  class CommandRecorder
16
- attr_accessor :commands, :delegate
17
+ include JoinTable
18
+
19
+ attr_accessor :commands, :delegate, :reverting
17
20
 
18
21
  def initialize(delegate = nil)
19
22
  @commands = []
20
23
  @delegate = delegate
24
+ @reverting = false
25
+ end
26
+
27
+ # While executing the given block, the recorded will be in reverting mode.
28
+ # All commands recorded will end up being recorded reverted
29
+ # and in reverse order.
30
+ # For example:
31
+ #
32
+ # recorder.revert{ recorder.record(:rename_table, [:old, :new]) }
33
+ # # same effect as recorder.record(:rename_table, [:new, :old])
34
+ def revert
35
+ @reverting = !@reverting
36
+ previous = @commands
37
+ @commands = []
38
+ yield
39
+ ensure
40
+ @commands = previous.concat(@commands.reverse)
41
+ @reverting = !@reverting
21
42
  end
22
43
 
23
44
  # record +command+. +command+ should be a method name and arguments.
24
45
  # For example:
25
46
  #
26
47
  # recorder.record(:method_name, [:arg1, :arg2])
27
- def record(*command)
28
- @commands << command
48
+ def record(*command, &block)
49
+ if @reverting
50
+ @commands << inverse_of(*command, &block)
51
+ else
52
+ @commands << (command << block)
53
+ end
29
54
  end
30
55
 
31
- # Returns a list that represents commands that are the inverse of the
32
- # commands stored in +commands+. For example:
56
+ # Returns the inverse of the given command. For example:
33
57
  #
34
- # recorder.record(:rename_table, [:old, :new])
35
- # recorder.inverse # => [:rename_table, [:new, :old]]
58
+ # recorder.inverse_of(:rename_table, [:old, :new])
59
+ # # => [:rename_table, [:new, :old]]
36
60
  #
37
61
  # This method will raise an +IrreversibleMigration+ exception if it cannot
38
- # invert the +commands+.
39
- def inverse
40
- @commands.reverse.map { |name, args|
41
- method = :"invert_#{name}"
42
- raise IrreversibleMigration unless respond_to?(method, true)
43
- send(method, args)
44
- }
62
+ # invert the +command+.
63
+ def inverse_of(command, args, &block)
64
+ method = :"invert_#{command}"
65
+ raise IrreversibleMigration unless respond_to?(method, true)
66
+ send(method, args, &block)
45
67
  end
46
68
 
47
69
  def respond_to?(*args) # :nodoc:
48
70
  super || delegate.respond_to?(*args)
49
71
  end
50
72
 
51
- [:create_table, :change_table, :rename_table, :add_column, :remove_column, :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps, :change_column, :change_column_default].each do |method|
73
+ [:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
74
+ :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
75
+ :change_column_default, :add_reference, :remove_reference, :transaction,
76
+ :drop_join_table, :drop_table, :execute_block, :enable_extension,
77
+ :change_column, :execute, :remove_columns, :change_column_null,
78
+ :add_foreign_key, :remove_foreign_key
79
+ # irreversible methods need to be here too
80
+ ].each do |method|
52
81
  class_eval <<-EOV, __FILE__, __LINE__ + 1
53
- def #{method}(*args) # def create_table(*args)
54
- record(:"#{method}", args) # record(:create_table, args)
55
- end # end
82
+ def #{method}(*args, &block) # def create_table(*args, &block)
83
+ record(:"#{method}", args, &block) # record(:create_table, args, &block)
84
+ end # end
56
85
  EOV
57
86
  end
87
+ alias :add_belongs_to :add_reference
88
+ alias :remove_belongs_to :remove_reference
89
+
90
+ def change_table(table_name, options = {}) # :nodoc:
91
+ yield delegate.update_table_definition(table_name, self)
92
+ end
58
93
 
59
94
  private
60
95
 
61
- def invert_create_table(args)
62
- [:drop_table, [args.first]]
96
+ module StraightReversions
97
+ private
98
+ { transaction: :transaction,
99
+ execute_block: :execute_block,
100
+ create_table: :drop_table,
101
+ create_join_table: :drop_join_table,
102
+ add_column: :remove_column,
103
+ add_timestamps: :remove_timestamps,
104
+ add_reference: :remove_reference,
105
+ enable_extension: :disable_extension
106
+ }.each do |cmd, inv|
107
+ [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
108
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
109
+ def invert_#{method}(args, &block) # def invert_create_table(args, &block)
110
+ [:#{inverse}, args, block] # [:drop_table, args, block]
111
+ end # end
112
+ EOV
113
+ end
114
+ end
115
+ end
116
+
117
+ include StraightReversions
118
+
119
+ def invert_drop_table(args, &block)
120
+ if args.size == 1 && block == nil
121
+ raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
122
+ end
123
+ super
63
124
  end
64
125
 
65
126
  def invert_rename_table(args)
66
127
  [:rename_table, args.reverse]
67
128
  end
68
129
 
69
- def invert_add_column(args)
70
- [:remove_column, args.first(2)]
130
+ def invert_remove_column(args)
131
+ raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2
132
+ super
71
133
  end
72
134
 
73
135
  def invert_rename_index(args)
@@ -80,26 +142,56 @@ module ActiveRecord
80
142
 
81
143
  def invert_add_index(args)
82
144
  table, columns, options = *args
83
- index_name = options.try(:[], :name)
84
- options_hash = index_name ? {:name => index_name} : {:column => columns}
145
+ options ||= {}
146
+
147
+ index_name = options[:name]
148
+ options_hash = index_name ? { name: index_name } : { column: columns }
149
+
85
150
  [:remove_index, [table, options_hash]]
86
151
  end
87
152
 
88
- def invert_remove_timestamps(args)
89
- [:add_timestamps, args]
153
+ def invert_remove_index(args)
154
+ table, options = *args
155
+
156
+ unless options && options.is_a?(Hash) && options[:column]
157
+ raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
158
+ end
159
+
160
+ options = options.dup
161
+ [:add_index, [table, options.delete(:column), options]]
162
+ end
163
+
164
+ alias :invert_add_belongs_to :invert_add_reference
165
+ alias :invert_remove_belongs_to :invert_remove_reference
166
+
167
+ def invert_change_column_null(args)
168
+ args[2] = !args[2]
169
+ [:change_column_null, args]
90
170
  end
91
171
 
92
- def invert_add_timestamps(args)
93
- [:remove_timestamps, args]
172
+ def invert_add_foreign_key(args)
173
+ from_table, to_table, add_options = args
174
+ add_options ||= {}
175
+
176
+ if add_options[:name]
177
+ options = { name: add_options[:name] }
178
+ elsif add_options[:column]
179
+ options = { column: add_options[:column] }
180
+ else
181
+ options = to_table
182
+ end
183
+
184
+ [:remove_foreign_key, [from_table, options]]
94
185
  end
95
186
 
96
187
  # Forwards any missing method call to the \target.
97
188
  def method_missing(method, *args, &block)
98
- @delegate.send(method, *args, &block)
99
- rescue NoMethodError => e
100
- raise e, e.message.sub(/ for #<.*$/, " via proxy for #{@delegate}")
189
+ if @delegate.respond_to?(method)
190
+ @delegate.send(method, *args, &block)
191
+ else
192
+ super
193
+ end
101
194
  end
102
-
103
195
  end
104
196
  end
105
197
  end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ class Migration
3
+ module JoinTable #:nodoc:
4
+ private
5
+
6
+ def find_join_table_name(table_1, table_2, options = {})
7
+ options.delete(:table_name) || join_table_name(table_1, table_2)
8
+ end
9
+
10
+ def join_table_name(table_1, table_2)
11
+ ModelSchema.derive_join_table_name(table_1, table_2).to_sym
12
+ end
13
+ end
14
+ end
15
+ end