activerecord 4.1.8 → 4.2.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (186) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1165 -1591
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +15 -8
  5. data/lib/active_record/association_relation.rb +13 -0
  6. data/lib/active_record/associations/alias_tracker.rb +3 -12
  7. data/lib/active_record/associations/association.rb +16 -4
  8. data/lib/active_record/associations/association_scope.rb +84 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -14
  14. data/lib/active_record/associations/builder/has_many.rb +1 -1
  15. data/lib/active_record/associations/builder/has_one.rb +2 -2
  16. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  17. data/lib/active_record/associations/collection_association.rb +87 -30
  18. data/lib/active_record/associations/collection_proxy.rb +33 -35
  19. data/lib/active_record/associations/foreign_association.rb +11 -0
  20. data/lib/active_record/associations/has_many_association.rb +83 -22
  21. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  22. data/lib/active_record/associations/has_one_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  24. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -12
  26. data/lib/active_record/associations/preloader/association.rb +14 -10
  27. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  28. data/lib/active_record/associations/preloader.rb +37 -26
  29. data/lib/active_record/associations/singular_association.rb +17 -2
  30. data/lib/active_record/associations/through_association.rb +16 -12
  31. data/lib/active_record/associations.rb +158 -49
  32. data/lib/active_record/attribute.rb +163 -0
  33. data/lib/active_record/attribute_assignment.rb +20 -12
  34. data/lib/active_record/attribute_decorators.rb +66 -0
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  37. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  38. data/lib/active_record/attribute_methods/query.rb +1 -1
  39. data/lib/active_record/attribute_methods/read.rb +22 -59
  40. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -28
  42. data/lib/active_record/attribute_methods/write.rb +9 -24
  43. data/lib/active_record/attribute_methods.rb +57 -95
  44. data/lib/active_record/attribute_set/builder.rb +106 -0
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attributes.rb +147 -0
  47. data/lib/active_record/autosave_association.rb +30 -12
  48. data/lib/active_record/base.rb +13 -24
  49. data/lib/active_record/callbacks.rb +6 -6
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +85 -53
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +139 -57
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
  62. data/lib/active_record/connection_adapters/column.rb +29 -240
  63. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +17 -33
  65. data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
  66. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  67. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  69. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -385
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  97. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +134 -43
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  101. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  103. data/lib/active_record/connection_handling.rb +1 -1
  104. data/lib/active_record/core.rb +163 -40
  105. data/lib/active_record/counter_cache.rb +60 -6
  106. data/lib/active_record/enum.rb +10 -12
  107. data/lib/active_record/errors.rb +53 -30
  108. data/lib/active_record/explain.rb +1 -1
  109. data/lib/active_record/explain_subscriber.rb +1 -1
  110. data/lib/active_record/fixtures.rb +62 -74
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +35 -10
  113. data/lib/active_record/integration.rb +4 -4
  114. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  115. data/lib/active_record/locking/optimistic.rb +46 -26
  116. data/lib/active_record/migration/command_recorder.rb +19 -2
  117. data/lib/active_record/migration/join_table.rb +1 -1
  118. data/lib/active_record/migration.rb +79 -47
  119. data/lib/active_record/model_schema.rb +52 -58
  120. data/lib/active_record/nested_attributes.rb +18 -8
  121. data/lib/active_record/no_touching.rb +1 -1
  122. data/lib/active_record/persistence.rb +48 -27
  123. data/lib/active_record/query_cache.rb +3 -3
  124. data/lib/active_record/querying.rb +10 -7
  125. data/lib/active_record/railtie.rb +19 -14
  126. data/lib/active_record/railties/databases.rake +55 -56
  127. data/lib/active_record/readonly_attributes.rb +0 -1
  128. data/lib/active_record/reflection.rb +281 -117
  129. data/lib/active_record/relation/batches.rb +0 -1
  130. data/lib/active_record/relation/calculations.rb +41 -37
  131. data/lib/active_record/relation/delegation.rb +1 -1
  132. data/lib/active_record/relation/finder_methods.rb +71 -48
  133. data/lib/active_record/relation/merger.rb +39 -29
  134. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  135. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  136. data/lib/active_record/relation/predicate_builder.rb +42 -12
  137. data/lib/active_record/relation/query_methods.rb +130 -73
  138. data/lib/active_record/relation/spawn_methods.rb +10 -3
  139. data/lib/active_record/relation.rb +57 -25
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -8
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +54 -28
  155. data/lib/active_record/type/big_integer.rb +13 -0
  156. data/lib/active_record/type/binary.rb +50 -0
  157. data/lib/active_record/type/boolean.rb +31 -0
  158. data/lib/active_record/type/date.rb +50 -0
  159. data/lib/active_record/type/date_time.rb +54 -0
  160. data/lib/active_record/type/decimal.rb +64 -0
  161. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  162. data/lib/active_record/type/decorator.rb +14 -0
  163. data/lib/active_record/type/float.rb +19 -0
  164. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  165. data/lib/active_record/type/integer.rb +59 -0
  166. data/lib/active_record/type/mutable.rb +16 -0
  167. data/lib/active_record/type/numeric.rb +36 -0
  168. data/lib/active_record/type/serialized.rb +62 -0
  169. data/lib/active_record/type/string.rb +40 -0
  170. data/lib/active_record/type/text.rb +11 -0
  171. data/lib/active_record/type/time.rb +26 -0
  172. data/lib/active_record/type/time_value.rb +38 -0
  173. data/lib/active_record/type/type_map.rb +64 -0
  174. data/lib/active_record/type/unsigned_integer.rb +15 -0
  175. data/lib/active_record/type/value.rb +110 -0
  176. data/lib/active_record/type.rb +23 -0
  177. data/lib/active_record/validations/associated.rb +5 -3
  178. data/lib/active_record/validations/presence.rb +5 -3
  179. data/lib/active_record/validations/uniqueness.rb +24 -20
  180. data/lib/active_record/validations.rb +25 -19
  181. data/lib/active_record.rb +5 -0
  182. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  183. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  184. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  185. metadata +66 -11
  186. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/string/strip'
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  class AbstractAdapter
@@ -13,9 +15,7 @@ module ActiveRecord
13
15
  end
14
16
 
15
17
  def visit_AddColumn(o)
16
- sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
17
- sql = "ADD #{quote_column_name(o.name)} #{sql_type}"
18
- add_column_options!(sql, column_options(o))
18
+ "ADD #{accept(o)}"
19
19
  end
20
20
 
21
21
  private
@@ -23,10 +23,12 @@ module ActiveRecord
23
23
  def visit_AlterTable(o)
24
24
  sql = "ALTER TABLE #{quote_table_name(o.name)} "
25
25
  sql << o.adds.map { |col| visit_AddColumn col }.join(' ')
26
+ sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
27
+ sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
26
28
  end
27
29
 
28
30
  def visit_ColumnDefinition(o)
29
- sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
31
+ sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale)
30
32
  column_sql = "#{quote_column_name(o.name)} #{sql_type}"
31
33
  add_column_options!(column_sql, column_options(o)) unless o.primary_key?
32
34
  column_sql
@@ -41,6 +43,21 @@ module ActiveRecord
41
43
  create_sql
42
44
  end
43
45
 
46
+ def visit_AddForeignKey(o)
47
+ sql = <<-SQL.strip_heredoc
48
+ ADD CONSTRAINT #{quote_column_name(o.name)}
49
+ FOREIGN KEY (#{quote_column_name(o.column)})
50
+ REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
51
+ SQL
52
+ sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
53
+ sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
54
+ sql
55
+ end
56
+
57
+ def visit_DropForeignKey(name)
58
+ "DROP CONSTRAINT #{quote_column_name(name)}"
59
+ end
60
+
44
61
  def column_options(o)
45
62
  column_options = {}
46
63
  column_options[:null] = o.null unless o.null.nil?
@@ -77,6 +94,7 @@ module ActiveRecord
77
94
 
78
95
  def quote_value(value, column)
79
96
  column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale)
97
+ column.cast_type ||= type_for_column(column)
80
98
 
81
99
  @conn.quote(value, column)
82
100
  end
@@ -84,6 +102,23 @@ module ActiveRecord
84
102
  def options_include_default?(options)
85
103
  options.include?(:default) && !(options[:null] == false && options[:default].nil?)
86
104
  end
105
+
106
+ def action_sql(action, dependency)
107
+ case dependency
108
+ when :nullify then "ON #{action} SET NULL"
109
+ when :cascade then "ON #{action} CASCADE"
110
+ when :restrict then "ON #{action} RESTRICT"
111
+ else
112
+ raise ArgumentError, <<-MSG.strip_heredoc
113
+ '#{dependency}' is not supported for :on_update or :on_delete.
114
+ Supported values are: :nullify, :cascade, :restrict
115
+ MSG
116
+ end
117
+ end
118
+
119
+ def type_for_column(column)
120
+ @conn.lookup_cast_type(column.sql_type)
121
+ end
87
122
  end
88
123
  end
89
124
  end
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  # are typically created by methods in TableDefinition, and added to the
16
16
  # +columns+ attribute of said TableDefinition object, in order to be used
17
17
  # for generating a number of table creation or table changing SQL statements.
18
- class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type) #:nodoc:
18
+ class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type, :cast_type) #:nodoc:
19
19
 
20
20
  def primary_key?
21
21
  primary_key || type.to_sym == :primary_key
@@ -25,6 +25,49 @@ module ActiveRecord
25
25
  class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc:
26
26
  end
27
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]
43
+ end
44
+
45
+ def on_update
46
+ options[:on_update]
47
+ end
48
+
49
+ def custom_primary_key?
50
+ options[:primary_key] != default_primary_key
51
+ end
52
+
53
+ private
54
+ def default_primary_key
55
+ "id"
56
+ end
57
+ end
58
+
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
69
+ end
70
+
28
71
  # Represents the schema of an SQL table in an abstract way. This class
29
72
  # provides methods for manipulating the schema representation.
30
73
  #
@@ -46,14 +89,17 @@ module ActiveRecord
46
89
  # The table definitions
47
90
  # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
48
91
  class TableDefinition
92
+ include TimestampDefaultDeprecation
93
+
49
94
  # An array of ColumnDefinition objects, representing the column changes
50
95
  # that have been defined.
51
96
  attr_accessor :indexes
52
- attr_reader :name, :temporary, :options, :as
97
+ attr_reader :name, :temporary, :options, :as, :foreign_keys
53
98
 
54
99
  def initialize(types, name, temporary, options, as = nil)
55
100
  @columns_hash = {}
56
101
  @indexes = {}
102
+ @foreign_keys = []
57
103
  @native = types
58
104
  @temporary = temporary
59
105
  @options = options
@@ -79,8 +125,8 @@ module ActiveRecord
79
125
  # which is one of the following:
80
126
  # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
81
127
  # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
82
- # <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
83
- # <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>.
84
130
  #
85
131
  # You may use a type not in this list as long as it is supported by your
86
132
  # database (for example, "polygon" in MySQL), but this will not be database
@@ -99,9 +145,11 @@ module ActiveRecord
99
145
  # Specifies the precision for a <tt>:decimal</tt> column.
100
146
  # * <tt>:scale</tt> -
101
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.
102
150
  #
103
- # For clarity's sake: the precision is the number of significant digits,
104
- # 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
105
153
  # the decimal point. For example, the number 123.45 has a precision of 5
106
154
  # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
107
155
  # range from -999.99 to 999.99.
@@ -123,17 +171,8 @@ module ActiveRecord
123
171
  # Default is (38,0).
124
172
  # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
125
173
  # Default unknown.
126
- # * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
127
- # Default (9,0). Internal types NUMERIC and DECIMAL have different
128
- # storage rules, decimal being better.
129
- # * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
130
- # Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
131
- # NUMERIC is 19, and DECIMAL is 38.
132
174
  # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
133
175
  # Default (38,0).
134
- # * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
135
- # Default (38,0).
136
- # * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
137
176
  #
138
177
  # This method returns <tt>self</tt>.
139
178
  #
@@ -172,20 +211,23 @@ module ActiveRecord
172
211
  # What can be written like this with the regular calls to column:
173
212
  #
174
213
  # create_table :products do |t|
175
- # t.column :shop_id, :integer
176
- # t.column :creator_id, :integer
177
- # t.column :name, :string, default: "Untitled"
178
- # t.column :value, :string, default: "Untitled"
179
- # t.column :created_at, :datetime
180
- # t.column :updated_at, :datetime
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
181
221
  # end
222
+ # add_index :products, :item_number
182
223
  #
183
224
  # can also be written as follows using the short-hand:
184
225
  #
185
226
  # create_table :products do |t|
186
227
  # t.integer :shop_id, :creator_id
228
+ # t.string :item_number, index: true
187
229
  # t.string :name, :value, default: "Untitled"
188
- # t.timestamps
230
+ # t.timestamps null: false
189
231
  # end
190
232
  #
191
233
  # There's a short-hand method for each of the type values declared at the top. And then there's
@@ -214,11 +256,14 @@ module ActiveRecord
214
256
  def column(name, type, options = {})
215
257
  name = name.to_s
216
258
  type = type.to_sym
259
+ options = options.dup
217
260
 
218
- if primary_key_column_name == name
261
+ if @columns_hash[name] && @columns_hash[name].primary_key?
219
262
  raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
220
263
  end
221
264
 
265
+ index_options = options.delete(:index)
266
+ index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
222
267
  @columns_hash[name] = new_column_definition(name, type, options)
223
268
  self
224
269
  end
@@ -227,7 +272,7 @@ module ActiveRecord
227
272
  @columns_hash.delete name.to_s
228
273
  end
229
274
 
230
- [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
275
+ [:string, :text, :integer, :bigint, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
231
276
  define_method column_type do |*args|
232
277
  options = args.extract_options!
233
278
  column_names = args
@@ -243,34 +288,58 @@ module ActiveRecord
243
288
  indexes[column_name] = options
244
289
  end
245
290
 
291
+ def foreign_key(table_name, options = {}) # :nodoc:
292
+ foreign_keys.push([table_name, options])
293
+ end
294
+
246
295
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
247
- # <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
248
299
  def timestamps(*args)
249
300
  options = args.extract_options!
301
+ emit_warning_if_null_unspecified(:timestamps, options)
250
302
  column(:created_at, :datetime, options)
251
303
  column(:updated_at, :datetime, options)
252
304
  end
253
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.
254
312
  def references(*args)
255
313
  options = args.extract_options!
256
314
  polymorphic = options.delete(:polymorphic)
257
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
+
258
323
  args.each do |col|
259
- column("#{col}_id", :integer, options)
324
+ column("#{col}_id", type, options)
260
325
  column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
261
- index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
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
262
331
  end
263
332
  end
264
333
  alias :belongs_to :references
265
334
 
266
335
  def new_column_definition(name, type, options) # :nodoc:
336
+ type = aliased_types(type.to_s, type)
267
337
  column = create_column_definition name, type
268
338
  limit = options.fetch(:limit) do
269
339
  native[type][:limit] if native[type].is_a?(Hash)
270
340
  end
271
341
 
272
342
  column.limit = limit
273
- column.array = options[:array] if column.respond_to?(:array)
274
343
  column.precision = options[:precision]
275
344
  column.scale = options[:scale]
276
345
  column.default = options[:default]
@@ -286,26 +355,37 @@ module ActiveRecord
286
355
  ColumnDefinition.new name, type
287
356
  end
288
357
 
289
- def primary_key_column_name
290
- primary_key_column = columns.detect { |c| c.primary_key? }
291
- primary_key_column && primary_key_column.name
292
- end
293
-
294
358
  def native
295
359
  @native
296
360
  end
361
+
362
+ def aliased_types(name, fallback)
363
+ 'timestamp' == name ? :datetime : fallback
364
+ end
297
365
  end
298
366
 
299
367
  class AlterTable # :nodoc:
300
368
  attr_reader :adds
369
+ attr_reader :foreign_key_adds
370
+ attr_reader :foreign_key_drops
301
371
 
302
372
  def initialize(td)
303
373
  @td = td
304
374
  @adds = []
375
+ @foreign_key_adds = []
376
+ @foreign_key_drops = []
305
377
  end
306
378
 
307
379
  def name; @td.name; end
308
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
+
309
389
  def add_column(name, type, options)
310
390
  name = name.to_s
311
391
  type = type.to_sym
@@ -347,8 +427,10 @@ module ActiveRecord
347
427
  # end
348
428
  #
349
429
  class Table
430
+ attr_reader :name
431
+
350
432
  def initialize(table_name, base)
351
- @table_name = table_name
433
+ @name = table_name
352
434
  @base = base
353
435
  end
354
436
 
@@ -358,12 +440,12 @@ module ActiveRecord
358
440
  # ====== Creating a simple column
359
441
  # t.column(:name, :string)
360
442
  def column(column_name, type, options = {})
361
- @base.add_column(@table_name, column_name, type, options)
443
+ @base.add_column(name, column_name, type, options)
362
444
  end
363
445
 
364
446
  # Checks to see if a column exists. See SchemaStatements#column_exists?
365
447
  def column_exists?(column_name, type = nil, options = {})
366
- @base.column_exists?(@table_name, column_name, type, options)
448
+ @base.column_exists?(name, column_name, type, options)
367
449
  end
368
450
 
369
451
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
@@ -376,26 +458,26 @@ module ActiveRecord
376
458
  # ====== Creating a named index
377
459
  # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
378
460
  def index(column_name, options = {})
379
- @base.add_index(@table_name, column_name, options)
461
+ @base.add_index(name, column_name, options)
380
462
  end
381
463
 
382
464
  # Checks to see if an index exists. See SchemaStatements#index_exists?
383
465
  def index_exists?(column_name, options = {})
384
- @base.index_exists?(@table_name, column_name, options)
466
+ @base.index_exists?(name, column_name, options)
385
467
  end
386
468
 
387
469
  # Renames the given index on the table.
388
470
  #
389
471
  # t.rename_index(:user_id, :account_id)
390
472
  def rename_index(index_name, new_index_name)
391
- @base.rename_index(@table_name, index_name, new_index_name)
473
+ @base.rename_index(name, index_name, new_index_name)
392
474
  end
393
475
 
394
476
  # Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
395
477
  #
396
- # t.timestamps
397
- def timestamps
398
- @base.add_timestamps(@table_name)
478
+ # t.timestamps null: false
479
+ def timestamps(options = {})
480
+ @base.add_timestamps(name, options)
399
481
  end
400
482
 
401
483
  # Changes the column's definition according to the new options.
@@ -404,7 +486,7 @@ module ActiveRecord
404
486
  # t.change(:name, :string, limit: 80)
405
487
  # t.change(:description, :text)
406
488
  def change(column_name, type, options = {})
407
- @base.change_column(@table_name, column_name, type, options)
489
+ @base.change_column(name, column_name, type, options)
408
490
  end
409
491
 
410
492
  # Sets a new default value for a column. See SchemaStatements#change_column_default
@@ -412,7 +494,7 @@ module ActiveRecord
412
494
  # t.change_default(:qualification, 'new')
413
495
  # t.change_default(:authorized, 1)
414
496
  def change_default(column_name, default)
415
- @base.change_column_default(@table_name, column_name, default)
497
+ @base.change_column_default(name, column_name, default)
416
498
  end
417
499
 
418
500
  # Removes the column(s) from the table definition.
@@ -420,7 +502,7 @@ module ActiveRecord
420
502
  # t.remove(:qualification)
421
503
  # t.remove(:qualification, :experience)
422
504
  def remove(*column_names)
423
- @base.remove_columns(@table_name, *column_names)
505
+ @base.remove_columns(name, *column_names)
424
506
  end
425
507
 
426
508
  # Removes the given index from the table.
@@ -434,33 +516,33 @@ module ActiveRecord
434
516
  # ====== Remove the index named by_branch_party in the table_name table
435
517
  # t.remove_index name: :by_branch_party
436
518
  def remove_index(options = {})
437
- @base.remove_index(@table_name, options)
519
+ @base.remove_index(name, options)
438
520
  end
439
521
 
440
522
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
441
523
  #
442
524
  # t.remove_timestamps
443
- def remove_timestamps
444
- @base.remove_timestamps(@table_name)
525
+ def remove_timestamps(options = {})
526
+ @base.remove_timestamps(name, options)
445
527
  end
446
528
 
447
529
  # Renames a column.
448
530
  #
449
531
  # t.rename(:description, :name)
450
532
  def rename(column_name, new_column_name)
451
- @base.rename_column(@table_name, column_name, new_column_name)
533
+ @base.rename_column(name, column_name, new_column_name)
452
534
  end
453
535
 
454
- # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
455
- # <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
536
+ # Adds a reference.
456
537
  #
457
538
  # t.references(:user)
458
- # t.belongs_to(:supplier, polymorphic: true)
539
+ # t.belongs_to(:supplier, foreign_key: true)
459
540
  #
541
+ # See SchemaStatements#add_reference for details of the options you can use.
460
542
  def references(*args)
461
543
  options = args.extract_options!
462
544
  args.each do |ref_name|
463
- @base.add_reference(@table_name, ref_name, options)
545
+ @base.add_reference(name, ref_name, options)
464
546
  end
465
547
  end
466
548
  alias :belongs_to :references
@@ -471,10 +553,11 @@ module ActiveRecord
471
553
  # t.remove_references(:user)
472
554
  # t.remove_belongs_to(:supplier, polymorphic: true)
473
555
  #
556
+ # See SchemaStatements#remove_reference
474
557
  def remove_references(*args)
475
558
  options = args.extract_options!
476
559
  args.each do |ref_name|
477
- @base.remove_reference(@table_name, ref_name, options)
560
+ @base.remove_reference(name, ref_name, options)
478
561
  end
479
562
  end
480
563
  alias :remove_belongs_to :remove_references
@@ -486,8 +569,8 @@ module ActiveRecord
486
569
  [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
487
570
  define_method column_type do |*args|
488
571
  options = args.extract_options!
489
- args.each do |name|
490
- @base.add_column(@table_name, name, column_type, options)
572
+ args.each do |column_name|
573
+ @base.add_column(name, column_name, column_type, options)
491
574
  end
492
575
  end
493
576
  end
@@ -497,6 +580,5 @@ module ActiveRecord
497
580
  @base.native_database_types
498
581
  end
499
582
  end
500
-
501
583
  end
502
584
  end
@@ -1,5 +1,3 @@
1
- require 'ipaddr'
2
-
3
1
  module ActiveRecord
4
2
  module ConnectionAdapters # :nodoc:
5
3
  # The goal of this module is to move Adapter specific column
@@ -10,7 +8,7 @@ module ActiveRecord
10
8
  module ColumnDumper
11
9
  def column_spec(column, types)
12
10
  spec = prepare_column_options(column, types)
13
- (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.to_s}: ")}
11
+ (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k}: ")}
14
12
  spec
15
13
  end
16
14
 
@@ -20,19 +18,17 @@ module ActiveRecord
20
18
  def prepare_column_options(column, types)
21
19
  spec = {}
22
20
  spec[:name] = column.name.inspect
21
+ spec[:type] = column.type.to_s
22
+ spec[:null] = 'false' unless column.null
23
23
 
24
- # AR has an optimization which handles zero-scale decimals as integers. This
25
- # code ensures that the dumper still dumps the column as a decimal.
26
- spec[:type] = if column.type == :integer && /^(numeric|decimal)/ =~ column.sql_type
27
- 'decimal'
28
- else
29
- column.type.to_s
30
- end
31
- spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit] && spec[:type] != 'decimal'
24
+ limit = column.limit || types[column.type][:limit]
25
+ spec[:limit] = limit.inspect if limit
32
26
  spec[:precision] = column.precision.inspect if column.precision
33
27
  spec[:scale] = column.scale.inspect if column.scale
34
- spec[:null] = 'false' unless column.null
35
- spec[:default] = default_string(column.default) if column.has_default?
28
+
29
+ default = schema_default(column) if column.has_default?
30
+ spec[:default] = default unless default.nil?
31
+
36
32
  spec
37
33
  end
38
34
 
@@ -43,28 +39,12 @@ module ActiveRecord
43
39
 
44
40
  private
45
41
 
46
- def default_string(value)
47
- case value
48
- when BigDecimal
49
- value.to_s
50
- when Date, DateTime, Time
51
- "'#{value.to_s(:db)}'"
52
- when Range
53
- # infinity dumps as Infinity, which causes uninitialized constant error
54
- value.inspect.gsub('Infinity', '::Float::INFINITY')
55
- when IPAddr
56
- subnet_mask = value.instance_variable_get(:@mask_addr)
57
-
58
- # If the subnet mask is equal to /32, don't output it
59
- if subnet_mask == (2**32 - 1)
60
- "\"#{value.to_s}\""
61
- else
62
- "\"#{value.to_s}/#{subnet_mask.to_s(2).count('1')}\""
63
- end
64
- else
65
- value.inspect
66
- end
42
+ def schema_default(column)
43
+ default = column.type_cast_from_database(column.default)
44
+ unless default.nil?
45
+ column.type_cast_for_schema(default)
67
46
  end
47
+ end
68
48
  end
69
49
  end
70
50
  end