activerecord 2.1.2 → 2.2.2

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 (110) hide show
  1. data/CHANGELOG +32 -6
  2. data/README +0 -0
  3. data/Rakefile +4 -5
  4. data/lib/active_record.rb +11 -10
  5. data/lib/active_record/aggregations.rb +110 -38
  6. data/lib/active_record/association_preload.rb +104 -15
  7. data/lib/active_record/associations.rb +427 -212
  8. data/lib/active_record/associations/association_collection.rb +101 -16
  9. data/lib/active_record/associations/association_proxy.rb +65 -13
  10. data/lib/active_record/associations/belongs_to_association.rb +2 -2
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -0
  12. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -3
  13. data/lib/active_record/associations/has_many_association.rb +28 -28
  14. data/lib/active_record/associations/has_many_through_association.rb +21 -19
  15. data/lib/active_record/associations/has_one_association.rb +24 -7
  16. data/lib/active_record/associations/has_one_through_association.rb +3 -4
  17. data/lib/active_record/attribute_methods.rb +13 -5
  18. data/lib/active_record/base.rb +435 -212
  19. data/lib/active_record/calculations.rb +12 -5
  20. data/lib/active_record/callbacks.rb +28 -9
  21. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +355 -0
  22. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +42 -215
  23. data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -5
  24. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
  25. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +48 -7
  26. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +10 -4
  27. data/lib/active_record/connection_adapters/abstract_adapter.rb +67 -26
  28. data/lib/active_record/connection_adapters/mysql_adapter.rb +71 -45
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +155 -84
  30. data/lib/active_record/dirty.rb +25 -7
  31. data/lib/active_record/dynamic_finder_match.rb +41 -0
  32. data/lib/active_record/fixtures.rb +10 -9
  33. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  34. data/lib/active_record/locale/en.yml +54 -0
  35. data/lib/active_record/migration.rb +47 -10
  36. data/lib/active_record/named_scope.rb +29 -16
  37. data/lib/active_record/reflection.rb +118 -54
  38. data/lib/active_record/schema_dumper.rb +13 -7
  39. data/lib/active_record/test_case.rb +18 -5
  40. data/lib/active_record/transactions.rb +89 -34
  41. data/lib/active_record/validations.rb +270 -180
  42. data/lib/active_record/version.rb +1 -1
  43. data/test/cases/active_schema_test_mysql.rb +5 -0
  44. data/test/cases/adapter_test.rb +6 -0
  45. data/test/cases/aggregations_test.rb +39 -0
  46. data/test/cases/associations/belongs_to_associations_test.rb +10 -0
  47. data/test/cases/associations/eager_load_nested_include_test.rb +30 -12
  48. data/test/cases/associations/eager_test.rb +54 -5
  49. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +77 -10
  50. data/test/cases/associations/has_many_associations_test.rb +74 -7
  51. data/test/cases/associations/has_many_through_associations_test.rb +50 -3
  52. data/test/cases/associations/has_one_associations_test.rb +17 -0
  53. data/test/cases/associations/has_one_through_associations_test.rb +49 -1
  54. data/test/cases/associations_test.rb +0 -0
  55. data/test/cases/attribute_methods_test.rb +59 -4
  56. data/test/cases/base_test.rb +93 -21
  57. data/test/cases/binary_test.rb +1 -5
  58. data/test/cases/calculations_test.rb +5 -0
  59. data/test/cases/callbacks_observers_test.rb +38 -0
  60. data/test/cases/connection_test_mysql.rb +1 -1
  61. data/test/cases/defaults_test.rb +32 -1
  62. data/test/cases/deprecated_finder_test.rb +0 -0
  63. data/test/cases/dirty_test.rb +13 -0
  64. data/test/cases/finder_test.rb +162 -12
  65. data/test/cases/fixtures_test.rb +32 -3
  66. data/test/cases/helper.rb +15 -0
  67. data/test/cases/i18n_test.rb +41 -0
  68. data/test/cases/inheritance_test.rb +2 -2
  69. data/test/cases/lifecycle_test.rb +0 -0
  70. data/test/cases/locking_test.rb +4 -9
  71. data/test/cases/method_scoping_test.rb +109 -2
  72. data/test/cases/migration_test.rb +43 -8
  73. data/test/cases/multiple_db_test.rb +25 -0
  74. data/test/cases/named_scope_test.rb +74 -0
  75. data/test/cases/pooled_connections_test.rb +103 -0
  76. data/test/cases/readonly_test.rb +0 -0
  77. data/test/cases/reflection_test.rb +11 -3
  78. data/test/cases/reload_models_test.rb +20 -0
  79. data/test/cases/sanitize_test.rb +25 -0
  80. data/test/cases/schema_authorization_test_postgresql.rb +2 -2
  81. data/test/cases/transactions_test.rb +62 -12
  82. data/test/cases/unconnected_test.rb +0 -0
  83. data/test/cases/validations_i18n_test.rb +921 -0
  84. data/test/cases/validations_test.rb +44 -33
  85. data/test/connections/native_mysql/connection.rb +1 -3
  86. data/test/fixtures/companies.yml +1 -0
  87. data/test/fixtures/customers.yml +10 -1
  88. data/test/fixtures/fixture_database.sqlite3 +0 -0
  89. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  90. data/test/fixtures/organizations.yml +5 -0
  91. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  92. data/test/models/author.rb +3 -0
  93. data/test/models/category.rb +3 -0
  94. data/test/models/club.rb +6 -0
  95. data/test/models/company.rb +25 -1
  96. data/test/models/customer.rb +19 -1
  97. data/test/models/member.rb +2 -0
  98. data/test/models/member_detail.rb +4 -0
  99. data/test/models/organization.rb +4 -0
  100. data/test/models/parrot.rb +1 -0
  101. data/test/models/post.rb +3 -0
  102. data/test/models/reply.rb +0 -0
  103. data/test/models/topic.rb +3 -0
  104. data/test/schema/schema.rb +12 -1
  105. metadata +22 -10
  106. data/lib/active_record/vendor/mysql.rb +0 -1214
  107. data/test/cases/adapter_test_sqlserver.rb +0 -95
  108. data/test/cases/table_name_test_sqlserver.rb +0 -23
  109. data/test/cases/threaded_connections_test.rb +0 -48
  110. data/test/schema/sqlserver_specific_schema.rb +0 -5
@@ -1,5 +1,3 @@
1
- require 'set'
2
-
3
1
  module ActiveRecord
4
2
  class Base
5
3
  class ConnectionSpecification #:nodoc:
@@ -9,163 +7,9 @@ module ActiveRecord
9
7
  end
10
8
  end
11
9
 
12
- # Check for activity after at least +verification_timeout+ seconds.
13
- # Defaults to 0 (always check.)
14
- cattr_accessor :verification_timeout, :instance_writer => false
15
- @@verification_timeout = 0
16
-
17
- # The class -> [adapter_method, config] map
18
- @@defined_connections = {}
19
-
20
- # The class -> thread id -> adapter cache. (class -> adapter if not allow_concurrency)
21
- @@active_connections = {}
22
-
23
- class << self
24
- # Retrieve the connection cache.
25
- def thread_safe_active_connections #:nodoc:
26
- @@active_connections[Thread.current.object_id] ||= {}
27
- end
28
-
29
- def single_threaded_active_connections #:nodoc:
30
- @@active_connections
31
- end
32
-
33
- # pick up the right active_connection method from @@allow_concurrency
34
- if @@allow_concurrency
35
- alias_method :active_connections, :thread_safe_active_connections
36
- else
37
- alias_method :active_connections, :single_threaded_active_connections
38
- end
39
-
40
- # set concurrency support flag (not thread safe, like most of the methods in this file)
41
- def allow_concurrency=(threaded) #:nodoc:
42
- logger.debug "allow_concurrency=#{threaded}" if logger
43
- return if @@allow_concurrency == threaded
44
- clear_all_cached_connections!
45
- @@allow_concurrency = threaded
46
- method_prefix = threaded ? "thread_safe" : "single_threaded"
47
- sing = (class << self; self; end)
48
- [:active_connections, :scoped_methods].each do |method|
49
- sing.send(:alias_method, method, "#{method_prefix}_#{method}")
50
- end
51
- log_connections if logger
52
- end
53
-
54
- def active_connection_name #:nodoc:
55
- @active_connection_name ||=
56
- if active_connections[name] || @@defined_connections[name]
57
- name
58
- elsif self == ActiveRecord::Base
59
- nil
60
- else
61
- superclass.active_connection_name
62
- end
63
- end
64
-
65
- def clear_active_connection_name #:nodoc:
66
- @active_connection_name = nil
67
- subclasses.each { |klass| klass.clear_active_connection_name }
68
- end
69
-
70
- # Returns the connection currently associated with the class. This can
71
- # also be used to "borrow" the connection to do database work unrelated
72
- # to any of the specific Active Records.
73
- def connection
74
- if defined?(@active_connection_name) && (conn = active_connections[@active_connection_name])
75
- conn
76
- else
77
- # retrieve_connection sets the cache key.
78
- conn = retrieve_connection
79
- active_connections[@active_connection_name] = conn
80
- end
81
- end
82
-
83
- # Clears the cache which maps classes to connections.
84
- def clear_active_connections!
85
- clear_cache!(@@active_connections) do |name, conn|
86
- conn.disconnect!
87
- end
88
- end
89
-
90
- # Clears the cache which maps classes
91
- def clear_reloadable_connections!
92
- if @@allow_concurrency
93
- # With concurrent connections @@active_connections is
94
- # a hash keyed by thread id.
95
- @@active_connections.each do |thread_id, conns|
96
- conns.each do |name, conn|
97
- if conn.requires_reloading?
98
- conn.disconnect!
99
- @@active_connections[thread_id].delete(name)
100
- end
101
- end
102
- end
103
- else
104
- @@active_connections.each do |name, conn|
105
- if conn.requires_reloading?
106
- conn.disconnect!
107
- @@active_connections.delete(name)
108
- end
109
- end
110
- end
111
- end
112
-
113
- # Verify active connections.
114
- def verify_active_connections! #:nodoc:
115
- if @@allow_concurrency
116
- remove_stale_cached_threads!(@@active_connections) do |name, conn|
117
- conn.disconnect!
118
- end
119
- end
120
-
121
- active_connections.each_value do |connection|
122
- connection.verify!(@@verification_timeout)
123
- end
124
- end
125
-
126
- private
127
- def clear_cache!(cache, thread_id = nil, &block)
128
- if cache
129
- if @@allow_concurrency
130
- thread_id ||= Thread.current.object_id
131
- thread_cache, cache = cache, cache[thread_id]
132
- return unless cache
133
- end
134
-
135
- cache.each(&block) if block_given?
136
- cache.clear
137
- end
138
- ensure
139
- if thread_cache && @@allow_concurrency
140
- thread_cache.delete(thread_id)
141
- end
142
- end
143
-
144
- # Remove stale threads from the cache.
145
- def remove_stale_cached_threads!(cache, &block)
146
- stale = Set.new(cache.keys)
147
-
148
- Thread.list.each do |thread|
149
- stale.delete(thread.object_id) if thread.alive?
150
- end
151
-
152
- stale.each do |thread_id|
153
- clear_cache!(cache, thread_id, &block)
154
- end
155
- end
156
-
157
- def clear_all_cached_connections!
158
- if @@allow_concurrency
159
- @@active_connections.each_value do |connection_hash_for_thread|
160
- connection_hash_for_thread.each_value {|conn| conn.disconnect! }
161
- connection_hash_for_thread.clear
162
- end
163
- else
164
- @@active_connections.each_value {|conn| conn.disconnect! }
165
- end
166
- @@active_connections.clear
167
- end
168
- end
10
+ # The connection handler
11
+ cattr_accessor :connection_handler, :instance_writer => false
12
+ @@connection_handler = ConnectionAdapters::ConnectionHandler.new
169
13
 
170
14
  # Returns the connection currently associated with the class. This can
171
15
  # also be used to "borrow" the connection to do database work that isn't
@@ -208,9 +52,7 @@ module ActiveRecord
208
52
  raise AdapterNotSpecified unless defined? RAILS_ENV
209
53
  establish_connection(RAILS_ENV)
210
54
  when ConnectionSpecification
211
- clear_active_connection_name
212
- @active_connection_name = name
213
- @@defined_connections[name] = spec
55
+ @@connection_handler.establish_connection(name, spec)
214
56
  when Symbol, String
215
57
  if configuration = configurations[spec.to_s]
216
58
  establish_connection(configuration)
@@ -243,67 +85,52 @@ module ActiveRecord
243
85
  end
244
86
  end
245
87
 
246
- # Locate the connection of the nearest super class. This can be an
247
- # active or defined connection: if it is the latter, it will be
248
- # opened and set as the active connection for the class it was defined
249
- # for (not necessarily the current class).
250
- def self.retrieve_connection #:nodoc:
251
- # Name is nil if establish_connection hasn't been called for
252
- # some class along the inheritance chain up to AR::Base yet.
253
- if name = active_connection_name
254
- if conn = active_connections[name]
255
- # Verify the connection.
256
- conn.verify!(@@verification_timeout)
257
- elsif spec = @@defined_connections[name]
258
- # Activate this connection specification.
259
- klass = name.constantize
260
- klass.connection = spec
261
- conn = active_connections[name]
262
- end
88
+ class << self
89
+ # Deprecated and no longer has any effect.
90
+ def allow_concurrency
91
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_concurrency has been deprecated and no longer has any effect. Please remove all references to allow_concurrency.")
263
92
  end
264
93
 
265
- conn or raise ConnectionNotEstablished
266
- end
94
+ # Deprecated and no longer has any effect.
95
+ def allow_concurrency=(flag)
96
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_concurrency= has been deprecated and no longer has any effect. Please remove all references to allow_concurrency=.")
97
+ end
267
98
 
268
- # Returns true if a connection that's accessible to this class has already been opened.
269
- def self.connected?
270
- active_connections[active_connection_name] ? true : false
271
- end
99
+ # Deprecated and no longer has any effect.
100
+ def verification_timeout
101
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.verification_timeout has been deprecated and no longer has any effect. Please remove all references to verification_timeout.")
102
+ end
272
103
 
273
- # Remove the connection for this class. This will close the active
274
- # connection and the defined connection (if they exist). The result
275
- # can be used as an argument for establish_connection, for easily
276
- # re-establishing the connection.
277
- def self.remove_connection(klass=self)
278
- spec = @@defined_connections[klass.name]
279
- konn = active_connections[klass.name]
280
- @@defined_connections.delete_if { |key, value| value == spec }
281
- active_connections.delete_if { |key, value| value == konn }
282
- konn.disconnect! if konn
283
- spec.config if spec
284
- end
104
+ # Deprecated and no longer has any effect.
105
+ def verification_timeout=(flag)
106
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.verification_timeout= has been deprecated and no longer has any effect. Please remove all references to verification_timeout=.")
107
+ end
285
108
 
286
- # Set the connection for the class.
287
- def self.connection=(spec) #:nodoc:
288
- if spec.kind_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter)
289
- active_connections[name] = spec
290
- elsif spec.kind_of?(ConnectionSpecification)
291
- config = spec.config.reverse_merge(:allow_concurrency => @@allow_concurrency)
292
- self.connection = self.send(spec.adapter_method, config)
293
- elsif spec.nil?
294
- raise ConnectionNotEstablished
295
- else
296
- establish_connection spec
109
+ # Returns the connection currently associated with the class. This can
110
+ # also be used to "borrow" the connection to do database work unrelated
111
+ # to any of the specific Active Records.
112
+ def connection
113
+ retrieve_connection
297
114
  end
298
- end
299
115
 
300
- # connection state logging
301
- def self.log_connections #:nodoc:
302
- if logger
303
- logger.info "Defined connections: #{@@defined_connections.inspect}"
304
- logger.info "Active connections: #{active_connections.inspect}"
305
- logger.info "Active connection name: #{@active_connection_name}"
116
+ def connection_pool
117
+ connection_handler.retrieve_connection_pool(self)
306
118
  end
119
+
120
+ def retrieve_connection
121
+ connection_handler.retrieve_connection(self)
122
+ end
123
+
124
+ def connected?
125
+ connection_handler.connected?(self)
126
+ end
127
+
128
+ def remove_connection(klass = self)
129
+ connection_handler.remove_connection(klass)
130
+ end
131
+
132
+ delegate :clear_active_connections!, :clear_reloadable_connections!,
133
+ :clear_all_connections!,:verify_active_connections!, :to => :connection_handler
307
134
  end
308
135
  end
309
136
  end
@@ -98,8 +98,14 @@ module ActiveRecord
98
98
  add_limit_offset!(sql, options) if options
99
99
  end
100
100
 
101
- # Appends +LIMIT+ and +OFFSET+ options to an SQL statement.
101
+ # Appends +LIMIT+ and +OFFSET+ options to an SQL statement, or some SQL
102
+ # fragment that has the same semantics as LIMIT and OFFSET.
103
+ #
104
+ # +options+ must be a Hash which contains a +:limit+ option (required)
105
+ # and an +:offset+ option (optional).
106
+ #
102
107
  # This method *modifies* the +sql+ parameter.
108
+ #
103
109
  # ===== Examples
104
110
  # add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})
105
111
  # generates
@@ -114,10 +120,6 @@ module ActiveRecord
114
120
  sql
115
121
  end
116
122
 
117
- def sanitize_limit(limit)
118
- limit.to_s[/,/] ? limit.split(',').map{ |i| i.to_i }.join(',') : limit.to_i
119
- end
120
-
121
123
  # Appends a locking clause to an SQL statement.
122
124
  # This method *modifies* the +sql+ parameter.
123
125
  # # SELECT * FROM suppliers FOR UPDATE
@@ -149,6 +151,14 @@ module ActiveRecord
149
151
  "INSERT INTO #{quote_table_name(table_name)} VALUES(DEFAULT)"
150
152
  end
151
153
 
154
+ def case_sensitive_equality_operator
155
+ "="
156
+ end
157
+
158
+ def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
159
+ "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
160
+ end
161
+
152
162
  protected
153
163
  # Returns an array of record hashes with the column names as keys and
154
164
  # column values as values.
@@ -171,6 +181,21 @@ module ActiveRecord
171
181
  def delete_sql(sql, name = nil)
172
182
  update_sql(sql, name)
173
183
  end
184
+
185
+ # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
186
+ #
187
+ # +limit+ may be anything that can evaluate to a string via #to_s. It
188
+ # should look like an integer, or a comma-delimited list of integers.
189
+ #
190
+ # Returns the sanitized limit parameter, either as an integer, or as a
191
+ # string which contains a comma-delimited list of integers.
192
+ def sanitize_limit(limit)
193
+ if limit.to_s =~ /,/
194
+ limit.to_s.split(',').map{ |i| i.to_i }.join(',')
195
+ else
196
+ limit.to_i
197
+ end
198
+ end
174
199
  end
175
200
  end
176
201
  end
@@ -4,7 +4,6 @@ module ActiveRecord
4
4
  class << self
5
5
  def included(base)
6
6
  base.class_eval do
7
- attr_accessor :query_cache_enabled
8
7
  alias_method_chain :columns, :query_cache
9
8
  alias_method_chain :select_all, :query_cache
10
9
  end
@@ -26,6 +25,8 @@ module ActiveRecord
26
25
  end
27
26
  end
28
27
 
28
+ attr_reader :query_cache, :query_cache_enabled
29
+
29
30
  # Enable the query cache within the block.
30
31
  def cache
31
32
  old, @query_cache_enabled = @query_cache_enabled, true
@@ -1,4 +1,5 @@
1
1
  require 'date'
2
+ require 'set'
2
3
  require 'bigdecimal'
3
4
  require 'bigdecimal/util'
4
5
 
@@ -6,6 +7,8 @@ module ActiveRecord
6
7
  module ConnectionAdapters #:nodoc:
7
8
  # An abstract definition of a column in a table.
8
9
  class Column
10
+ TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
11
+
9
12
  module Format
10
13
  ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
11
14
  ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
@@ -30,11 +33,15 @@ module ActiveRecord
30
33
  end
31
34
 
32
35
  def text?
33
- [:string, :text].include? type
36
+ type == :string || type == :text
34
37
  end
35
38
 
36
39
  def number?
37
- [:float, :integer, :decimal].include? type
40
+ type == :integer || type == :float || type == :decimal
41
+ end
42
+
43
+ def has_default?
44
+ !default.nil?
38
45
  end
39
46
 
40
47
  # Returns the Ruby class that corresponds to the abstract data type.
@@ -135,10 +142,10 @@ module ActiveRecord
135
142
 
136
143
  # convert something to a boolean
137
144
  def value_to_boolean(value)
138
- if value == true || value == false
139
- value
145
+ if value.is_a?(String) && value.blank?
146
+ nil
140
147
  else
141
- %w(true t 1).include?(value.to_s.downcase)
148
+ TRUE_VALUES.include?(value)
142
149
  end
143
150
  end
144
151
 
@@ -249,6 +256,10 @@ module ActiveRecord
249
256
  class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc:
250
257
  end
251
258
 
259
+ # Abstract representation of a column definition. Instances of this type
260
+ # are typically created by methods in TableDefinition, and added to the
261
+ # +columns+ attribute of said TableDefinition object, in order to be used
262
+ # for generating a number of table creation or table changing SQL statements.
252
263
  class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
253
264
 
254
265
  def sql_type
@@ -272,9 +283,29 @@ module ActiveRecord
272
283
  end
273
284
  end
274
285
 
275
- # Represents a SQL table in an abstract way.
276
- # Columns are stored as a ColumnDefinition in the +columns+ attribute.
286
+ # Represents the schema of an SQL table in an abstract way. This class
287
+ # provides methods for manipulating the schema representation.
288
+ #
289
+ # Inside migration files, the +t+ object in +create_table+ and
290
+ # +change_table+ is actually of this type:
291
+ #
292
+ # class SomeMigration < ActiveRecord::Migration
293
+ # def self.up
294
+ # create_table :foo do |t|
295
+ # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
296
+ # end
297
+ # end
298
+ #
299
+ # def self.down
300
+ # ...
301
+ # end
302
+ # end
303
+ #
304
+ # The table definitions
305
+ # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
277
306
  class TableDefinition
307
+ # An array of ColumnDefinition objects, representing the column changes
308
+ # that have been defined.
278
309
  attr_accessor :columns
279
310
 
280
311
  def initialize(base)
@@ -318,6 +349,12 @@ module ActiveRecord
318
349
  # * <tt>:scale</tt> -
319
350
  # Specifies the scale for a <tt>:decimal</tt> column.
320
351
  #
352
+ # For clarity's sake: the precision is the number of significant digits,
353
+ # while the scale is the number of digits that can be stored following
354
+ # the decimal point. For example, the number 123.45 has a precision of 5
355
+ # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
356
+ # range from -999.99 to 999.99.
357
+ #
321
358
  # Please be aware of different RDBMS implementations behavior with
322
359
  # <tt>:decimal</tt> columns:
323
360
  # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
@@ -371,6 +408,10 @@ module ActiveRecord
371
408
  # td.column(:huge_integer, :decimal, :precision => 30)
372
409
  # # => huge_integer DECIMAL(30)
373
410
  #
411
+ # # Defines a column with a database-specific type.
412
+ # td.column(:foo, 'polygon')
413
+ # # => foo polygon
414
+ #
374
415
  # == Short-hand examples
375
416
  #
376
417
  # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.