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
@@ -1,4 +1,3 @@
1
- require 'active_support/core_ext/object/blank'
2
1
  require 'date'
3
2
  require 'set'
4
3
  require 'bigdecimal'
@@ -6,37 +5,67 @@ require 'bigdecimal/util'
6
5
 
7
6
  module ActiveRecord
8
7
  module ConnectionAdapters #:nodoc:
9
- class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders) #:nodoc:
8
+ # Abstract representation of an index definition on a table. Instances of
9
+ # this type are typically created and returned by methods in database
10
+ # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
11
+ class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using) #:nodoc:
10
12
  end
11
13
 
12
14
  # Abstract representation of a column definition. Instances of this type
13
15
  # are typically created by methods in TableDefinition, and added to the
14
16
  # +columns+ attribute of said TableDefinition object, in order to be used
15
17
  # for generating a number of table creation or table changing SQL statements.
16
- class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
18
+ class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type, :cast_type) #:nodoc:
17
19
 
18
- def string_to_binary(value)
19
- value
20
+ def primary_key?
21
+ primary_key || type.to_sym == :primary_key
22
+ end
23
+ end
24
+
25
+ class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc:
26
+ end
27
+
28
+ class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
29
+ def name
30
+ options[:name]
31
+ end
32
+
33
+ def column
34
+ options[:column]
35
+ end
36
+
37
+ def primary_key
38
+ options[:primary_key] || default_primary_key
39
+ end
40
+
41
+ def on_delete
42
+ options[:on_delete]
20
43
  end
21
44
 
22
- def sql_type
23
- base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
45
+ def on_update
46
+ options[:on_update]
24
47
  end
25
48
 
26
- def to_sql
27
- column_sql = "#{base.quote_column_name(name)} #{sql_type}"
28
- column_options = {}
29
- column_options[:null] = null unless null.nil?
30
- column_options[:default] = default unless default.nil?
31
- add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key
32
- column_sql
49
+ def custom_primary_key?
50
+ options[:primary_key] != default_primary_key
33
51
  end
34
52
 
35
53
  private
54
+ def default_primary_key
55
+ "id"
56
+ end
57
+ end
36
58
 
37
- def add_column_options!(sql, options)
38
- base.add_column_options!(sql, options.merge(:column => self))
39
- end
59
+ module TimestampDefaultDeprecation # :nodoc:
60
+ def emit_warning_if_null_unspecified(sym, options)
61
+ return if options.key?(:null)
62
+
63
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
64
+ `##{sym}` was called without specifying an option for `null`. In Rails 5,
65
+ this behavior will change to `null: false`. You should manually specify
66
+ `null: true` to prevent the behavior of your existing migrations from changing.
67
+ MSG
68
+ end
40
69
  end
41
70
 
42
71
  # Represents the schema of an SQL table in an abstract way. This class
@@ -60,29 +89,30 @@ module ActiveRecord
60
89
  # The table definitions
61
90
  # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
62
91
  class TableDefinition
92
+ include TimestampDefaultDeprecation
93
+
63
94
  # An array of ColumnDefinition objects, representing the column changes
64
95
  # that have been defined.
65
- attr_accessor :columns
96
+ attr_accessor :indexes
97
+ attr_reader :name, :temporary, :options, :as, :foreign_keys
66
98
 
67
- def initialize(base)
68
- @columns = []
99
+ def initialize(types, name, temporary, options, as = nil)
69
100
  @columns_hash = {}
70
- @base = base
101
+ @indexes = {}
102
+ @foreign_keys = []
103
+ @native = types
104
+ @temporary = temporary
105
+ @options = options
106
+ @as = as
107
+ @name = name
71
108
  end
72
109
 
73
- def xml(*args)
74
- raise NotImplementedError unless %w{
75
- sqlite mysql mysql2
76
- }.include? @base.adapter_name.downcase
77
-
78
- options = args.extract_options!
79
- column(args[0], :text, options)
80
- end
110
+ def columns; @columns_hash.values; end
81
111
 
82
112
  # Appends a primary key definition to the table definition.
83
113
  # Can be called multiple times, but this is probably not a good idea.
84
- def primary_key(name)
85
- column(name, :primary_key)
114
+ def primary_key(name, type = :primary_key, options = {})
115
+ column(name, type, options.merge(:primary_key => true))
86
116
  end
87
117
 
88
118
  # Returns a ColumnDefinition for the column with name +name+.
@@ -95,8 +125,8 @@ module ActiveRecord
95
125
  # which is one of the following:
96
126
  # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
97
127
  # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
98
- # <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
99
- # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>.
128
+ # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
129
+ # <tt>:binary</tt>, <tt>:boolean</tt>.
100
130
  #
101
131
  # You may use a type not in this list as long as it is supported by your
102
132
  # database (for example, "polygon" in MySQL), but this will not be database
@@ -115,9 +145,11 @@ module ActiveRecord
115
145
  # Specifies the precision for a <tt>:decimal</tt> column.
116
146
  # * <tt>:scale</tt> -
117
147
  # Specifies the scale for a <tt>:decimal</tt> column.
148
+ # * <tt>:index</tt> -
149
+ # Create an index for the column. Can be either <tt>true</tt> or an options hash.
118
150
  #
119
- # For clarity's sake: the precision is the number of significant digits,
120
- # while the scale is the number of digits that can be stored following
151
+ # Note: The precision is the total number of significant digits
152
+ # and the scale is the number of digits that can be stored following
121
153
  # the decimal point. For example, the number 123.45 has a precision of 5
122
154
  # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
123
155
  # range from -999.99 to 999.99.
@@ -139,17 +171,8 @@ module ActiveRecord
139
171
  # Default is (38,0).
140
172
  # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
141
173
  # Default unknown.
142
- # * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
143
- # Default (9,0). Internal types NUMERIC and DECIMAL have different
144
- # storage rules, decimal being better.
145
- # * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
146
- # Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
147
- # NUMERIC is 19, and DECIMAL is 38.
148
174
  # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
149
175
  # Default (38,0).
150
- # * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
151
- # Default (38,0).
152
- # * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
153
176
  #
154
177
  # This method returns <tt>self</tt>.
155
178
  #
@@ -158,21 +181,21 @@ module ActiveRecord
158
181
  # td.column(:granted, :boolean)
159
182
  # # granted BOOLEAN
160
183
  #
161
- # td.column(:picture, :binary, :limit => 2.megabytes)
184
+ # td.column(:picture, :binary, limit: 2.megabytes)
162
185
  # # => picture BLOB(2097152)
163
186
  #
164
- # td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
187
+ # td.column(:sales_stage, :string, limit: 20, default: 'new', null: false)
165
188
  # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
166
189
  #
167
- # td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
190
+ # td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
168
191
  # # => bill_gates_money DECIMAL(15,2)
169
192
  #
170
- # td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
193
+ # td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
171
194
  # # => sensor_reading DECIMAL(30,20)
172
195
  #
173
196
  # # While <tt>:scale</tt> defaults to zero on most databases, it
174
197
  # # probably wouldn't hurt to include it.
175
- # td.column(:huge_integer, :decimal, :precision => 30)
198
+ # td.column(:huge_integer, :decimal, precision: 30)
176
199
  # # => huge_integer DECIMAL(30)
177
200
  #
178
201
  # # Defines a column with a database-specific type.
@@ -187,21 +210,24 @@ module ActiveRecord
187
210
  #
188
211
  # What can be written like this with the regular calls to column:
189
212
  #
190
- # create_table "products", :force => true do |t|
191
- # t.column "shop_id", :integer
192
- # t.column "creator_id", :integer
193
- # t.column "name", :string, :default => "Untitled"
194
- # t.column "value", :string, :default => "Untitled"
195
- # t.column "created_at", :datetime
196
- # t.column "updated_at", :datetime
213
+ # create_table :products do |t|
214
+ # t.column :shop_id, :integer
215
+ # t.column :creator_id, :integer
216
+ # t.column :item_number, :string
217
+ # t.column :name, :string, default: "Untitled"
218
+ # t.column :value, :string, default: "Untitled"
219
+ # t.column :created_at, :datetime
220
+ # t.column :updated_at, :datetime
197
221
  # end
222
+ # add_index :products, :item_number
198
223
  #
199
- # Can also be written as follows using the short-hand:
224
+ # can also be written as follows using the short-hand:
200
225
  #
201
226
  # create_table :products do |t|
202
227
  # t.integer :shop_id, :creator_id
203
- # t.string :name, :value, :default => "Untitled"
204
- # t.timestamps
228
+ # t.string :item_number, index: true
229
+ # t.string :name, :value, default: "Untitled"
230
+ # t.timestamps null: false
205
231
  # end
206
232
  #
207
233
  # There's a short-hand method for each of the type values declared at the top. And then there's
@@ -209,85 +235,161 @@ module ActiveRecord
209
235
  #
210
236
  # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
211
237
  # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
212
- # options, these will be used when creating the <tt>_type</tt> column. So what can be written like this:
238
+ # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
239
+ # will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
213
240
  #
214
241
  # create_table :taggings do |t|
215
242
  # t.integer :tag_id, :tagger_id, :taggable_id
216
243
  # t.string :tagger_type
217
- # t.string :taggable_type, :default => 'Photo'
244
+ # t.string :taggable_type, default: 'Photo'
218
245
  # end
246
+ # add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id'
247
+ # add_index :taggings, [:tagger_id, :tagger_type]
219
248
  #
220
249
  # Can also be written as follows using references:
221
250
  #
222
251
  # create_table :taggings do |t|
223
- # t.references :tag
224
- # t.references :tagger, :polymorphic => true
225
- # t.references :taggable, :polymorphic => { :default => 'Photo' }
252
+ # t.references :tag, index: { name: 'index_taggings_on_tag_id' }
253
+ # t.references :tagger, polymorphic: true, index: true
254
+ # t.references :taggable, polymorphic: { default: 'Photo' }
226
255
  # end
227
256
  def column(name, type, options = {})
228
257
  name = name.to_s
229
258
  type = type.to_sym
259
+ options = options.dup
230
260
 
231
- column = self[name] || new_column_definition(@base, name, type)
232
-
233
- limit = options.fetch(:limit) do
234
- native[type][:limit] if native[type].is_a?(Hash)
261
+ if @columns_hash[name] && @columns_hash[name].primary_key?
262
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
235
263
  end
236
264
 
237
- column.limit = limit
238
- column.precision = options[:precision]
239
- column.scale = options[:scale]
240
- column.default = options[:default]
241
- column.null = options[:null]
265
+ index_options = options.delete(:index)
266
+ index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
267
+ @columns_hash[name] = new_column_definition(name, type, options)
242
268
  self
243
269
  end
244
270
 
245
- %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
246
- class_eval <<-EOV, __FILE__, __LINE__ + 1
247
- def #{column_type}(*args) # def string(*args)
248
- options = args.extract_options! # options = args.extract_options!
249
- column_names = args # column_names = args
250
- type = :'#{column_type}' # type = :string
251
- column_names.each { |name| column(name, type, options) } # column_names.each { |name| column(name, type, options) }
252
- end # end
253
- EOV
271
+ def remove_column(name)
272
+ @columns_hash.delete name.to_s
273
+ end
274
+
275
+ [:string, :text, :integer, :bigint, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
276
+ define_method column_type do |*args|
277
+ options = args.extract_options!
278
+ column_names = args
279
+ column_names.each { |name| column(name, column_type, options) }
280
+ end
281
+ end
282
+
283
+ # Adds index options to the indexes hash, keyed by column name
284
+ # This is primarily used to track indexes that need to be created after the table
285
+ #
286
+ # index(:account_id, name: 'index_projects_on_account_id')
287
+ def index(column_name, options = {})
288
+ indexes[column_name] = options
289
+ end
290
+
291
+ def foreign_key(table_name, options = {}) # :nodoc:
292
+ foreign_keys.push([table_name, options])
254
293
  end
255
294
 
256
295
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
257
- # <tt>:updated_at</tt> to the table.
296
+ # <tt>:updated_at</tt> to the table. See SchemaStatements#add_timestamps
297
+ #
298
+ # t.timestamps null: false
258
299
  def timestamps(*args)
259
- options = { :null => false }.merge(args.extract_options!)
300
+ options = args.extract_options!
301
+ emit_warning_if_null_unspecified(:timestamps, options)
260
302
  column(:created_at, :datetime, options)
261
303
  column(:updated_at, :datetime, options)
262
304
  end
263
305
 
306
+ # Adds a reference.
307
+ #
308
+ # t.references(:user)
309
+ # t.belongs_to(:supplier, foreign_key: true)
310
+ #
311
+ # See SchemaStatements#add_reference for details of the options you can use.
264
312
  def references(*args)
265
313
  options = args.extract_options!
266
314
  polymorphic = options.delete(:polymorphic)
315
+ index_options = options.delete(:index)
316
+ foreign_key_options = options.delete(:foreign_key)
317
+ type = options.delete(:type) || :integer
318
+
319
+ if polymorphic && foreign_key_options
320
+ raise ArgumentError, "Cannot add a foreign key on a polymorphic relation"
321
+ end
322
+
267
323
  args.each do |col|
268
- column("#{col}_id", :integer, options)
269
- column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
324
+ column("#{col}_id", type, options)
325
+ column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
326
+ index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
327
+ if foreign_key_options
328
+ to_table = Base.pluralize_table_names ? col.to_s.pluralize : col.to_s
329
+ foreign_key(to_table, foreign_key_options.is_a?(Hash) ? foreign_key_options : {})
330
+ end
270
331
  end
271
332
  end
272
333
  alias :belongs_to :references
273
334
 
274
- # Returns a String whose contents are the column definitions
275
- # concatenated together. This string can then be prepended and appended to
276
- # to generate the final SQL to create the table.
277
- def to_sql
278
- @columns.map { |c| c.to_sql } * ', '
335
+ def new_column_definition(name, type, options) # :nodoc:
336
+ type = aliased_types(type.to_s, type)
337
+ column = create_column_definition name, type
338
+ limit = options.fetch(:limit) do
339
+ native[type][:limit] if native[type].is_a?(Hash)
340
+ end
341
+
342
+ column.limit = limit
343
+ column.precision = options[:precision]
344
+ column.scale = options[:scale]
345
+ column.default = options[:default]
346
+ column.null = options[:null]
347
+ column.first = options[:first]
348
+ column.after = options[:after]
349
+ column.primary_key = type == :primary_key || options[:primary_key]
350
+ column
279
351
  end
280
352
 
281
353
  private
282
- def new_column_definition(base, name, type)
283
- definition = ColumnDefinition.new base, name, type
284
- @columns << definition
285
- @columns_hash[name] = definition
286
- definition
354
+ def create_column_definition(name, type)
355
+ ColumnDefinition.new name, type
287
356
  end
288
357
 
289
358
  def native
290
- @base.native_database_types
359
+ @native
360
+ end
361
+
362
+ def aliased_types(name, fallback)
363
+ 'timestamp' == name ? :datetime : fallback
364
+ end
365
+ end
366
+
367
+ class AlterTable # :nodoc:
368
+ attr_reader :adds
369
+ attr_reader :foreign_key_adds
370
+ attr_reader :foreign_key_drops
371
+
372
+ def initialize(td)
373
+ @td = td
374
+ @adds = []
375
+ @foreign_key_adds = []
376
+ @foreign_key_drops = []
377
+ end
378
+
379
+ def name; @td.name; end
380
+
381
+ def add_foreign_key(to_table, options)
382
+ @foreign_key_adds << ForeignKeyDefinition.new(name, to_table, options)
383
+ end
384
+
385
+ def drop_foreign_key(name)
386
+ @foreign_key_drops << name
387
+ end
388
+
389
+ def add_column(name, type, options)
390
+ name = name.to_s
391
+ type = type.to_sym
392
+ @adds << @td.new_column_definition(name, type, options)
291
393
  end
292
394
  end
293
395
 
@@ -299,6 +401,7 @@ module ActiveRecord
299
401
  # change_table :table do |t|
300
402
  # t.column
301
403
  # t.index
404
+ # t.rename_index
302
405
  # t.timestamps
303
406
  # t.change
304
407
  # t.change_default
@@ -324,162 +427,152 @@ module ActiveRecord
324
427
  # end
325
428
  #
326
429
  class Table
430
+ attr_reader :name
431
+
327
432
  def initialize(table_name, base)
328
- @table_name = table_name
433
+ @name = table_name
329
434
  @base = base
330
435
  end
331
436
 
332
437
  # Adds a new column to the named table.
333
438
  # See TableDefinition#column for details of the options you can use.
334
- # ===== Example
439
+ #
335
440
  # ====== Creating a simple column
336
441
  # t.column(:name, :string)
337
442
  def column(column_name, type, options = {})
338
- @base.add_column(@table_name, column_name, type, options)
443
+ @base.add_column(name, column_name, type, options)
339
444
  end
340
445
 
341
446
  # Checks to see if a column exists. See SchemaStatements#column_exists?
342
447
  def column_exists?(column_name, type = nil, options = {})
343
- @base.column_exists?(@table_name, column_name, type, options)
448
+ @base.column_exists?(name, column_name, type, options)
344
449
  end
345
450
 
346
451
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
347
452
  # an Array of Symbols. See SchemaStatements#add_index
348
453
  #
349
- # ===== Examples
350
454
  # ====== Creating a simple index
351
455
  # t.index(:name)
352
456
  # ====== Creating a unique index
353
- # t.index([:branch_id, :party_id], :unique => true)
457
+ # t.index([:branch_id, :party_id], unique: true)
354
458
  # ====== Creating a named index
355
- # t.index([:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
459
+ # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
356
460
  def index(column_name, options = {})
357
- @base.add_index(@table_name, column_name, options)
461
+ @base.add_index(name, column_name, options)
358
462
  end
359
463
 
360
464
  # Checks to see if an index exists. See SchemaStatements#index_exists?
361
465
  def index_exists?(column_name, options = {})
362
- @base.index_exists?(@table_name, column_name, options)
466
+ @base.index_exists?(name, column_name, options)
467
+ end
468
+
469
+ # Renames the given index on the table.
470
+ #
471
+ # t.rename_index(:user_id, :account_id)
472
+ def rename_index(index_name, new_index_name)
473
+ @base.rename_index(name, index_name, new_index_name)
363
474
  end
364
475
 
365
476
  # Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
366
- # ===== Example
367
- # t.timestamps
368
- def timestamps
369
- @base.add_timestamps(@table_name)
477
+ #
478
+ # t.timestamps null: false
479
+ def timestamps(options = {})
480
+ @base.add_timestamps(name, options)
370
481
  end
371
482
 
372
483
  # Changes the column's definition according to the new options.
373
484
  # See TableDefinition#column for details of the options you can use.
374
- # ===== Examples
375
- # t.change(:name, :string, :limit => 80)
485
+ #
486
+ # t.change(:name, :string, limit: 80)
376
487
  # t.change(:description, :text)
377
488
  def change(column_name, type, options = {})
378
- @base.change_column(@table_name, column_name, type, options)
489
+ @base.change_column(name, column_name, type, options)
379
490
  end
380
491
 
381
492
  # Sets a new default value for a column. See SchemaStatements#change_column_default
382
- # ===== Examples
493
+ #
383
494
  # t.change_default(:qualification, 'new')
384
495
  # t.change_default(:authorized, 1)
385
496
  def change_default(column_name, default)
386
- @base.change_column_default(@table_name, column_name, default)
497
+ @base.change_column_default(name, column_name, default)
387
498
  end
388
499
 
389
500
  # Removes the column(s) from the table definition.
390
- # ===== Examples
501
+ #
391
502
  # t.remove(:qualification)
392
503
  # t.remove(:qualification, :experience)
393
504
  def remove(*column_names)
394
- @base.remove_column(@table_name, *column_names)
505
+ @base.remove_columns(name, *column_names)
395
506
  end
396
507
 
397
508
  # Removes the given index from the table.
398
509
  #
399
- # ===== Examples
400
510
  # ====== Remove the index_table_name_on_column in the table_name table
401
511
  # t.remove_index :column
402
512
  # ====== Remove the index named index_table_name_on_branch_id in the table_name table
403
- # t.remove_index :column => :branch_id
513
+ # t.remove_index column: :branch_id
404
514
  # ====== Remove the index named index_table_name_on_branch_id_and_party_id in the table_name table
405
- # t.remove_index :column => [:branch_id, :party_id]
515
+ # t.remove_index column: [:branch_id, :party_id]
406
516
  # ====== Remove the index named by_branch_party in the table_name table
407
- # t.remove_index :name => :by_branch_party
517
+ # t.remove_index name: :by_branch_party
408
518
  def remove_index(options = {})
409
- @base.remove_index(@table_name, options)
519
+ @base.remove_index(name, options)
410
520
  end
411
521
 
412
522
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
413
- # ===== Example
523
+ #
414
524
  # t.remove_timestamps
415
- def remove_timestamps
416
- @base.remove_timestamps(@table_name)
525
+ def remove_timestamps(options = {})
526
+ @base.remove_timestamps(name, options)
417
527
  end
418
528
 
419
529
  # Renames a column.
420
- # ===== Example
530
+ #
421
531
  # t.rename(:description, :name)
422
532
  def rename(column_name, new_column_name)
423
- @base.rename_column(@table_name, column_name, new_column_name)
533
+ @base.rename_column(name, column_name, new_column_name)
424
534
  end
425
535
 
426
- # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
427
- # <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
428
- # ===== Examples
429
- # t.references(:goat)
430
- # t.references(:goat, :polymorphic => true)
431
- # t.belongs_to(:goat)
536
+ # Adds a reference.
537
+ #
538
+ # t.references(:user)
539
+ # t.belongs_to(:supplier, foreign_key: true)
540
+ #
541
+ # See SchemaStatements#add_reference for details of the options you can use.
432
542
  def references(*args)
433
543
  options = args.extract_options!
434
- polymorphic = options.delete(:polymorphic)
435
- args.each do |col|
436
- @base.add_column(@table_name, "#{col}_id", :integer, options)
437
- @base.add_column(@table_name, "#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
544
+ args.each do |ref_name|
545
+ @base.add_reference(name, ref_name, options)
438
546
  end
439
547
  end
440
548
  alias :belongs_to :references
441
549
 
442
550
  # Removes a reference. Optionally removes a +type+ column.
443
551
  # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
444
- # ===== Examples
445
- # t.remove_references(:goat)
446
- # t.remove_references(:goat, :polymorphic => true)
447
- # t.remove_belongs_to(:goat)
552
+ #
553
+ # t.remove_references(:user)
554
+ # t.remove_belongs_to(:supplier, polymorphic: true)
555
+ #
556
+ # See SchemaStatements#remove_reference
448
557
  def remove_references(*args)
449
558
  options = args.extract_options!
450
- polymorphic = options.delete(:polymorphic)
451
- args.each do |col|
452
- @base.remove_column(@table_name, "#{col}_id")
453
- @base.remove_column(@table_name, "#{col}_type") unless polymorphic.nil?
559
+ args.each do |ref_name|
560
+ @base.remove_reference(name, ref_name, options)
454
561
  end
455
562
  end
456
- alias :remove_belongs_to :remove_references
563
+ alias :remove_belongs_to :remove_references
457
564
 
458
565
  # Adds a column or columns of a specified type
459
- # ===== Examples
566
+ #
460
567
  # t.string(:goat)
461
568
  # t.string(:goat, :sheep)
462
- %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
463
- class_eval <<-EOV, __FILE__, __LINE__ + 1
464
- def #{column_type}(*args) # def string(*args)
465
- options = args.extract_options! # options = args.extract_options!
466
- column_names = args # column_names = args
467
- type = :'#{column_type}' # type = :string
468
- column_names.each do |name| # column_names.each do |name|
469
- column = ColumnDefinition.new(@base, name.to_s, type) # column = ColumnDefinition.new(@base, name, type)
470
- if options[:limit] # if options[:limit]
471
- column.limit = options[:limit] # column.limit = options[:limit]
472
- elsif native[type].is_a?(Hash) # elsif native[type].is_a?(Hash)
473
- column.limit = native[type][:limit] # column.limit = native[type][:limit]
474
- end # end
475
- column.precision = options[:precision] # column.precision = options[:precision]
476
- column.scale = options[:scale] # column.scale = options[:scale]
477
- column.default = options[:default] # column.default = options[:default]
478
- column.null = options[:null] # column.null = options[:null]
479
- @base.add_column(@table_name, name, column.sql_type, options) # @base.add_column(@table_name, name, column.sql_type, options)
480
- end # end
481
- end # end
482
- EOV
569
+ [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
570
+ define_method column_type do |*args|
571
+ options = args.extract_options!
572
+ args.each do |column_name|
573
+ @base.add_column(name, column_name, column_type, options)
574
+ end
575
+ end
483
576
  end
484
577
 
485
578
  private
@@ -487,6 +580,5 @@ module ActiveRecord
487
580
  @base.native_database_types
488
581
  end
489
582
  end
490
-
491
583
  end
492
584
  end