activerecord 4.2.1 → 4.2.7.1

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +368 -1
  3. data/lib/active_record/aggregations.rb +4 -3
  4. data/lib/active_record/association_relation.rb +13 -0
  5. data/lib/active_record/associations/association.rb +15 -3
  6. data/lib/active_record/associations/association_scope.rb +1 -0
  7. data/lib/active_record/associations/belongs_to_association.rb +5 -1
  8. data/lib/active_record/associations/builder/association.rb +1 -1
  9. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -4
  10. data/lib/active_record/associations/collection_association.rb +1 -7
  11. data/lib/active_record/associations/collection_proxy.rb +8 -7
  12. data/lib/active_record/associations/has_many_association.rb +8 -1
  13. data/lib/active_record/associations/has_many_through_association.rb +9 -0
  14. data/lib/active_record/associations/join_dependency.rb +8 -2
  15. data/lib/active_record/associations/preloader/association.rb +5 -1
  16. data/lib/active_record/associations/preloader.rb +4 -4
  17. data/lib/active_record/associations/singular_association.rb +2 -8
  18. data/lib/active_record/associations/through_association.rb +0 -6
  19. data/lib/active_record/associations.rb +1 -1
  20. data/lib/active_record/attribute_assignment.rb +1 -1
  21. data/lib/active_record/attribute_methods/dirty.rb +7 -1
  22. data/lib/active_record/attribute_methods.rb +3 -7
  23. data/lib/active_record/attribute_set/builder.rb +21 -11
  24. data/lib/active_record/attribute_set.rb +4 -0
  25. data/lib/active_record/autosave_association.rb +1 -1
  26. data/lib/active_record/base.rb +4 -5
  27. data/lib/active_record/callbacks.rb +1 -1
  28. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +4 -0
  29. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -2
  30. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -24
  31. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +49 -17
  32. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +12 -1
  34. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +38 -5
  35. data/lib/active_record/connection_adapters/column.rb +1 -1
  36. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -3
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -2
  38. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  39. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  40. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  41. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -6
  42. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -9
  43. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -12
  44. data/lib/active_record/core.rb +15 -8
  45. data/lib/active_record/enum.rb +2 -3
  46. data/lib/active_record/errors.rb +6 -5
  47. data/lib/active_record/explain_subscriber.rb +1 -1
  48. data/lib/active_record/fixtures.rb +8 -6
  49. data/lib/active_record/gem_version.rb +2 -2
  50. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  51. data/lib/active_record/migration.rb +7 -4
  52. data/lib/active_record/model_schema.rb +1 -1
  53. data/lib/active_record/nested_attributes.rb +12 -2
  54. data/lib/active_record/persistence.rb +5 -3
  55. data/lib/active_record/railtie.rb +1 -1
  56. data/lib/active_record/railties/databases.rake +10 -7
  57. data/lib/active_record/reflection.rb +39 -27
  58. data/lib/active_record/relation/calculations.rb +8 -1
  59. data/lib/active_record/relation/delegation.rb +1 -1
  60. data/lib/active_record/relation/finder_methods.rb +3 -15
  61. data/lib/active_record/relation/merger.rb +24 -1
  62. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -1
  63. data/lib/active_record/relation/predicate_builder.rb +11 -2
  64. data/lib/active_record/relation/query_methods.rb +15 -18
  65. data/lib/active_record/relation/spawn_methods.rb +7 -3
  66. data/lib/active_record/relation.rb +2 -1
  67. data/lib/active_record/scoping/default.rb +1 -0
  68. data/lib/active_record/tasks/database_tasks.rb +3 -2
  69. data/lib/active_record/tasks/mysql_database_tasks.rb +30 -16
  70. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -8
  71. data/lib/active_record/transactions.rb +16 -4
  72. data/lib/active_record/type/boolean.rb +1 -0
  73. data/lib/active_record/type/date.rb +4 -0
  74. data/lib/active_record/type/decimal.rb +12 -2
  75. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  76. data/lib/active_record/type/serialized.rb +7 -1
  77. data/lib/active_record/validations/uniqueness.rb +15 -5
  78. data/lib/active_record.rb +2 -0
  79. metadata +9 -7
@@ -10,13 +10,13 @@ module ActiveRecord
10
10
  # end
11
11
  #
12
12
  # class Book < ActiveRecord::Base
13
- # # columns: title, sales
13
+ # # columns: title, sales, author_id
14
14
  # end
15
15
  #
16
16
  # When you load an author with all associated books Active Record will make
17
17
  # multiple queries like this:
18
18
  #
19
- # Author.includes(:books).where(:name => ['bell hooks', 'Homer').to_a
19
+ # Author.includes(:books).where(name: ['bell hooks', 'Homer']).to_a
20
20
  #
21
21
  # => SELECT `authors`.* FROM `authors` WHERE `name` IN ('bell hooks', 'Homer')
22
22
  # => SELECT `books`.* FROM `books` WHERE `author_id` IN (2, 5)
@@ -160,7 +160,7 @@ module ActiveRecord
160
160
  h
161
161
  end
162
162
 
163
- class AlreadyLoaded
163
+ class AlreadyLoaded # :nodoc:
164
164
  attr_reader :owners, :reflection
165
165
 
166
166
  def initialize(klass, owners, reflection, preload_scope)
@@ -175,7 +175,7 @@ module ActiveRecord
175
175
  end
176
176
  end
177
177
 
178
- class NullPreloader
178
+ class NullPreloader # :nodoc:
179
179
  def self.new(klass, owners, reflection, preload_scope); self; end
180
180
  def self.run(preloader); end
181
181
  def self.preloaded_records; []; end
@@ -3,7 +3,7 @@ module ActiveRecord
3
3
  class SingularAssociation < Association #:nodoc:
4
4
  # Implements the reader method, e.g. foo.bar for Foo.has_one :bar
5
5
  def reader(force_reload = false)
6
- if force_reload
6
+ if force_reload && klass
7
7
  klass.uncached { reload }
8
8
  elsif !loaded? || stale_target?
9
9
  reload
@@ -39,13 +39,7 @@ module ActiveRecord
39
39
  end
40
40
 
41
41
  def get_records
42
- if reflection.scope_chain.any?(&:any?) ||
43
- scope.eager_loading? ||
44
- klass.current_scope ||
45
- klass.default_scopes.any?
46
-
47
- return scope.limit(1).to_a
48
- end
42
+ return scope.limit(1).to_a if skip_statement_cache?
49
43
 
50
44
  conn = klass.connection
51
45
  sc = reflection.association_scope_cache(conn, owner) do
@@ -15,12 +15,6 @@ module ActiveRecord
15
15
  scope = super
16
16
  reflection.chain.drop(1).each do |reflection|
17
17
  relation = reflection.klass.all
18
-
19
- reflection_scope = reflection.scope
20
- if reflection_scope && reflection_scope.arity.zero?
21
- relation.merge!(reflection_scope)
22
- end
23
-
24
18
  scope.merge!(
25
19
  relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
26
20
  )
@@ -1713,7 +1713,7 @@ module ActiveRecord
1713
1713
  hm_options[:through] = middle_reflection.name
1714
1714
  hm_options[:source] = join_model.right_reflection.name
1715
1715
 
1716
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name].each do |k|
1716
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
1717
1717
  hm_options[k] = options[k] if options.key? k
1718
1718
  end
1719
1719
 
@@ -52,7 +52,7 @@ module ActiveRecord
52
52
 
53
53
  def _assign_attribute(k, v)
54
54
  public_send("#{k}=", v)
55
- rescue NoMethodError
55
+ rescue NoMethodError, NameError
56
56
  if respond_to?("#{k}=")
57
57
  raise
58
58
  else
@@ -40,6 +40,7 @@ module ActiveRecord
40
40
 
41
41
  def initialize_dup(other) # :nodoc:
42
42
  super
43
+ @original_raw_attributes = nil
43
44
  calculate_changes_from_defaults
44
45
  end
45
46
 
@@ -108,6 +109,7 @@ module ActiveRecord
108
109
  end
109
110
 
110
111
  def save_changed_attribute(attr, old_value)
112
+ clear_changed_attributes_cache
111
113
  if attribute_changed_by_setter?(attr)
112
114
  clear_attribute_changes(attr) unless _field_changed?(attr, old_value)
113
115
  else
@@ -178,7 +180,11 @@ module ActiveRecord
178
180
  @cached_changed_attributes = changed_attributes
179
181
  yield
180
182
  ensure
181
- remove_instance_variable(:@cached_changed_attributes)
183
+ clear_changed_attributes_cache
184
+ end
185
+
186
+ def clear_changed_attributes_cache
187
+ remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
182
188
  end
183
189
  end
184
190
  end
@@ -287,9 +287,8 @@ module ActiveRecord
287
287
  # Returns an <tt>#inspect</tt>-like string for the value of the
288
288
  # attribute +attr_name+. String attributes are truncated up to 50
289
289
  # characters, Date and Time attributes are returned in the
290
- # <tt>:db</tt> format, Array attributes are truncated up to 10 values.
291
- # Other attributes return the value of <tt>#inspect</tt> without
292
- # modification.
290
+ # <tt>:db</tt> format. Other attributes return the value of
291
+ # <tt>#inspect</tt> without modification.
293
292
  #
294
293
  # person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
295
294
  #
@@ -300,7 +299,7 @@ module ActiveRecord
300
299
  # # => "\"2012-10-22 00:15:07\""
301
300
  #
302
301
  # person.attribute_for_inspect(:tag_ids)
303
- # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]"
302
+ # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
304
303
  def attribute_for_inspect(attr_name)
305
304
  value = read_attribute(attr_name)
306
305
 
@@ -308,9 +307,6 @@ module ActiveRecord
308
307
  "#{value[0, 50]}...".inspect
309
308
  elsif value.is_a?(Date) || value.is_a?(Time)
310
309
  %("#{value.to_s(:db)}")
311
- elsif value.is_a?(Array) && value.size > 10
312
- inspected = value.first(10).inspect
313
- %(#{inspected[0...-1]}, ...])
314
310
  else
315
311
  value.inspect
316
312
  end
@@ -1,3 +1,5 @@
1
+ require 'active_record/attribute'
2
+
1
3
  module ActiveRecord
2
4
  class AttributeSet # :nodoc:
3
5
  class Builder # :nodoc:
@@ -64,10 +66,29 @@ module ActiveRecord
64
66
  end
65
67
  end
66
68
 
69
+ def ==(other)
70
+ if other.is_a?(LazyAttributeHash)
71
+ materialize == other.materialize
72
+ else
73
+ materialize == other
74
+ end
75
+ end
76
+
67
77
  protected
68
78
 
69
79
  attr_reader :types, :values, :additional_types, :delegate_hash
70
80
 
81
+ def materialize
82
+ unless @materialized
83
+ values.each_key { |key| self[key] }
84
+ types.each_key { |key| self[key] }
85
+ unless frozen?
86
+ @materialized = true
87
+ end
88
+ end
89
+ delegate_hash
90
+ end
91
+
71
92
  private
72
93
 
73
94
  def assign_default_value(name)
@@ -81,16 +102,5 @@ module ActiveRecord
81
102
  delegate_hash[name] = Attribute.uninitialized(name, type)
82
103
  end
83
104
  end
84
-
85
- def materialize
86
- unless @materialized
87
- values.each_key { |key| self[key] }
88
- types.each_key { |key| self[key] }
89
- unless frozen?
90
- @materialized = true
91
- end
92
- end
93
- delegate_hash
94
- end
95
105
  end
96
106
  end
@@ -64,6 +64,10 @@ module ActiveRecord
64
64
  end
65
65
  end
66
66
 
67
+ def ==(other)
68
+ attributes == other.attributes
69
+ end
70
+
67
71
  protected
68
72
 
69
73
  attr_reader :attributes
@@ -318,7 +318,7 @@ module ActiveRecord
318
318
  # the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt>
319
319
  # enabled records if they're marked_for_destruction? or destroyed.
320
320
  def association_valid?(reflection, record)
321
- return true if record.destroyed? || record.marked_for_destruction?
321
+ return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
322
322
 
323
323
  validation_context = self.validation_context unless [:create, :update].include?(self.validation_context)
324
324
  unless valid = record.valid?(validation_context)
@@ -119,23 +119,22 @@ module ActiveRecord #:nodoc:
119
119
  # All column values are automatically available through basic accessors on the Active Record
120
120
  # object, but sometimes you want to specialize this behavior. This can be done by overwriting
121
121
  # the default accessors (using the same name as the attribute) and calling
122
- # <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually
123
- # change things.
122
+ # +super+ to actually change things.
124
123
  #
125
124
  # class Song < ActiveRecord::Base
126
125
  # # Uses an integer of seconds to hold the length of the song
127
126
  #
128
127
  # def length=(minutes)
129
- # write_attribute(:length, minutes.to_i * 60)
128
+ # super(minutes.to_i * 60)
130
129
  # end
131
130
  #
132
131
  # def length
133
- # read_attribute(:length) / 60
132
+ # super / 60
134
133
  # end
135
134
  # end
136
135
  #
137
136
  # You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt>
138
- # instead of <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
137
+ # or <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
139
138
  #
140
139
  # == Attribute query methods
141
140
  #
@@ -199,7 +199,7 @@ module ActiveRecord
199
199
  # == Canceling callbacks
200
200
  #
201
201
  # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
202
- # cancelled. If an <tt>after_*</tt> callback returns +false+, all the later callbacks are cancelled.
202
+ # cancelled.
203
203
  # Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
204
204
  # methods on the model, which are called last.
205
205
  #
@@ -456,6 +456,10 @@ module ActiveRecord
456
456
  c.verify!
457
457
  end
458
458
  c
459
+ rescue
460
+ remove c
461
+ c.disconnect!
462
+ raise
459
463
  end
460
464
  end
461
465
 
@@ -234,6 +234,10 @@ module ActiveRecord
234
234
  current_transaction.add_record(record)
235
235
  end
236
236
 
237
+ def transaction_state
238
+ current_transaction.state
239
+ end
240
+
237
241
  # Begins the transaction (and turns off auto-committing).
238
242
  def begin_db_transaction() end
239
243
 
@@ -283,12 +287,17 @@ module ActiveRecord
283
287
  # Inserts the given fixture into the table. Overridden in adapters that require
284
288
  # something beyond a simple insert (eg. Oracle).
285
289
  def insert_fixture(fixture, table_name)
290
+ fixture = fixture.stringify_keys
286
291
  columns = schema_cache.columns_hash(table_name)
287
292
 
288
293
  key_list = []
289
294
  value_list = fixture.map do |name, value|
290
- key_list << quote_column_name(name)
291
- quote(value, columns[name])
295
+ if column = columns[name]
296
+ key_list << quote_column_name(name)
297
+ quote(value, column)
298
+ else
299
+ raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
300
+ end
292
301
  end
293
302
 
294
303
  execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
@@ -57,11 +57,11 @@ module ActiveRecord
57
57
  end
58
58
 
59
59
  module TimestampDefaultDeprecation # :nodoc:
60
- def emit_warning_if_null_unspecified(options)
60
+ def emit_warning_if_null_unspecified(sym, options)
61
61
  return if options.key?(:null)
62
62
 
63
63
  ActiveSupport::Deprecation.warn(<<-MSG.squish)
64
- `#timestamp` was called without specifying an option for `null`. In Rails 5,
64
+ `##{sym}` was called without specifying an option for `null`. In Rails 5,
65
65
  this behavior will change to `null: false`. You should manually specify
66
66
  `null: true` to prevent the behavior of your existing migrations from changing.
67
67
  MSG
@@ -99,7 +99,7 @@ module ActiveRecord
99
99
  def initialize(types, name, temporary, options, as = nil)
100
100
  @columns_hash = {}
101
101
  @indexes = {}
102
- @foreign_keys = {}
102
+ @foreign_keys = []
103
103
  @native = types
104
104
  @temporary = temporary
105
105
  @options = options
@@ -256,6 +256,7 @@ module ActiveRecord
256
256
  def column(name, type, options = {})
257
257
  name = name.to_s
258
258
  type = type.to_sym
259
+ options = options.dup
259
260
 
260
261
  if @columns_hash[name] && @columns_hash[name].primary_key?
261
262
  raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
@@ -288,7 +289,7 @@ module ActiveRecord
288
289
  end
289
290
 
290
291
  def foreign_key(table_name, options = {}) # :nodoc:
291
- foreign_keys[table_name] = options
292
+ foreign_keys.push([table_name, options])
292
293
  end
293
294
 
294
295
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
@@ -297,23 +298,17 @@ module ActiveRecord
297
298
  # t.timestamps null: false
298
299
  def timestamps(*args)
299
300
  options = args.extract_options!
300
- emit_warning_if_null_unspecified(options)
301
+ emit_warning_if_null_unspecified(:timestamps, options)
301
302
  column(:created_at, :datetime, options)
302
303
  column(:updated_at, :datetime, options)
303
304
  end
304
305
 
305
- # Adds a reference. Optionally adds a +type+ column, if
306
- # <tt>:polymorphic</tt> option is provided. <tt>references</tt> and
307
- # <tt>belongs_to</tt> are acceptable. The reference column will be an
308
- # +integer+ by default, the <tt>:type</tt> option can be used to specify
309
- # a different type. A foreign key will be created if a +foreign_key+
310
- # option is passed.
306
+ # Adds a reference.
311
307
  #
312
308
  # t.references(:user)
313
- # t.references(:user, type: "string")
314
- # t.belongs_to(:supplier, polymorphic: true)
309
+ # t.belongs_to(:supplier, foreign_key: true)
315
310
  #
316
- # See SchemaStatements#add_reference
311
+ # See SchemaStatements#add_reference for details of the options you can use.
317
312
  def references(*args)
318
313
  options = args.extract_options!
319
314
  polymorphic = options.delete(:polymorphic)
@@ -329,7 +324,10 @@ module ActiveRecord
329
324
  column("#{col}_id", type, options)
330
325
  column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
331
326
  index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
332
- foreign_key(col.to_s.pluralize, foreign_key_options.is_a?(Hash) ? foreign_key_options : {}) if foreign_key_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
333
331
  end
334
332
  end
335
333
  alias :belongs_to :references
@@ -535,18 +533,12 @@ module ActiveRecord
535
533
  @base.rename_column(name, column_name, new_column_name)
536
534
  end
537
535
 
538
- # Adds a reference. Optionally adds a +type+ column, if
539
- # <tt>:polymorphic</tt> option is provided. <tt>references</tt> and
540
- # <tt>belongs_to</tt> are acceptable. The reference column will be an
541
- # +integer+ by default, the <tt>:type</tt> option can be used to specify
542
- # a different type. A foreign key will be created if a +foreign_key+
543
- # option is passed.
536
+ # Adds a reference.
544
537
  #
545
538
  # t.references(:user)
546
- # t.references(:user, type: "string")
547
- # t.belongs_to(:supplier, polymorphic: true)
539
+ # t.belongs_to(:supplier, foreign_key: true)
548
540
  #
549
- # See SchemaStatements#add_reference
541
+ # See SchemaStatements#add_reference for details of the options you can use.
550
542
  def references(*args)
551
543
  options = args.extract_options!
552
544
  args.each do |ref_name|
@@ -19,6 +19,20 @@ module ActiveRecord
19
19
  table_name[0...table_alias_length].tr('.', '_')
20
20
  end
21
21
 
22
+ # Returns the relation names useable to back Active Record models.
23
+ # For most adapters this means all tables and views.
24
+ def data_sources
25
+ tables
26
+ end
27
+
28
+ # Checks to see if the data source +name+ exists on the database.
29
+ #
30
+ # data_source_exists?(:ebooks)
31
+ #
32
+ def data_source_exists?(name)
33
+ data_sources.include?(name.to_s)
34
+ end
35
+
22
36
  # Checks to see if the table +table_name+ exists on the database.
23
37
  #
24
38
  # table_exists?(:developers)
@@ -213,7 +227,7 @@ module ActiveRecord
213
227
  end
214
228
  end
215
229
 
216
- td.foreign_keys.each_pair do |other_table_name, foreign_key_options|
230
+ td.foreign_keys.each do |other_table_name, foreign_key_options|
217
231
  add_foreign_key(table_name, other_table_name, foreign_key_options)
218
232
  end
219
233
 
@@ -530,6 +544,8 @@ module ActiveRecord
530
544
  #
531
545
  # CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
532
546
  #
547
+ # Note: Partial indexes are only supported for PostgreSQL and SQLite 3.8.0+.
548
+ #
533
549
  # ====== Creating an index with a specific method
534
550
  #
535
551
  # add_index(:developers, :name, using: 'btree')
@@ -621,11 +637,21 @@ module ActiveRecord
621
637
  indexes(table_name).detect { |i| i.name == index_name }
622
638
  end
623
639
 
624
- # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
625
- # The reference column is an +integer+ by default, the <tt>:type</tt> option can be used to specify
626
- # a different type.
640
+ # Adds a reference. The reference column is an integer by default,
641
+ # the <tt>:type</tt> option can be used to specify a different type.
642
+ # Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
627
643
  # <tt>add_reference</tt> and <tt>add_belongs_to</tt> are acceptable.
628
644
  #
645
+ # The +options+ hash can include the following keys:
646
+ # [<tt>:type</tt>]
647
+ # The reference column type. Defaults to +:integer+.
648
+ # [<tt>:index</tt>]
649
+ # Add an appropriate index. Defaults to false.
650
+ # [<tt>:foreign_key</tt>]
651
+ # Add an appropriate foreign key. Defaults to false.
652
+ # [<tt>:polymorphic</tt>]
653
+ # Wether an additional +_type+ column should be added. Defaults to false.
654
+ #
629
655
  # ====== Create a user_id integer column
630
656
  #
631
657
  # add_reference(:products, :user)
@@ -634,10 +660,6 @@ module ActiveRecord
634
660
  #
635
661
  # add_reference(:products, :user, type: :string)
636
662
  #
637
- # ====== Create a supplier_id and supplier_type columns
638
- #
639
- # add_belongs_to(:products, :supplier, polymorphic: true)
640
- #
641
663
  # ====== Create supplier_id, supplier_type columns and appropriate index
642
664
  #
643
665
  # add_reference(:products, :supplier, polymorphic: true, index: true)
@@ -655,7 +677,10 @@ module ActiveRecord
655
677
  add_column(table_name, "#{ref_name}_id", type, options)
656
678
  add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
657
679
  add_index(table_name, polymorphic ? %w[type id].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
658
- add_foreign_key(table_name, ref_name.to_s.pluralize, foreign_key_options.is_a?(Hash) ? foreign_key_options : {}) if foreign_key_options
680
+ if foreign_key_options
681
+ to_table = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
682
+ add_foreign_key(table_name, to_table, foreign_key_options.is_a?(Hash) ? foreign_key_options : {})
683
+ end
659
684
  end
660
685
  alias :add_belongs_to :add_reference
661
686
 
@@ -675,7 +700,10 @@ module ActiveRecord
675
700
  # remove_reference(:products, :user, index: true, foreign_key: true)
676
701
  #
677
702
  def remove_reference(table_name, ref_name, options = {})
678
- remove_foreign_key table_name, ref_name.to_s.pluralize if options[:foreign_key]
703
+ if options[:foreign_key]
704
+ to_table = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
705
+ remove_foreign_key(table_name, to_table)
706
+ end
679
707
 
680
708
  remove_column(table_name, "#{ref_name}_id")
681
709
  remove_column(table_name, "#{ref_name}_type") if options[:polymorphic]
@@ -692,8 +720,8 @@ module ActiveRecord
692
720
  # +to_table+ contains the referenced primary key.
693
721
  #
694
722
  # The foreign key will be named after the following pattern: <tt>fk_rails_<identifier></tt>.
695
- # +identifier+ is a 10 character long random string. A custom name can be specified with
696
- # the <tt>:name</tt> option.
723
+ # +identifier+ is a 10 character long string which is deterministically generated from the
724
+ # +from_table+ and +column+. A custom name can be specified with the <tt>:name</tt> option.
697
725
  #
698
726
  # ====== Creating a simple foreign key
699
727
  #
@@ -705,7 +733,7 @@ module ActiveRecord
705
733
  #
706
734
  # ====== Creating a foreign key on a specific column
707
735
  #
708
- # add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
736
+ # add_foreign_key :articles, :users, column: :author_id, primary_key: :lng_id
709
737
  #
710
738
  # generates:
711
739
  #
@@ -788,7 +816,10 @@ module ActiveRecord
788
816
  end
789
817
 
790
818
  def foreign_key_column_for(table_name) # :nodoc:
791
- "#{table_name.to_s.singularize}_id"
819
+ prefix = Base.table_name_prefix
820
+ suffix = Base.table_name_suffix
821
+ name = table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
822
+ "#{name.singularize}_id"
792
823
  end
793
824
 
794
825
  def dump_schema_information #:nodoc:
@@ -859,11 +890,12 @@ module ActiveRecord
859
890
  end
860
891
 
861
892
  # Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT.
862
- # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax - they
893
+ # PostgreSQL, MySQL, and Oracle overrides this for custom DISTINCT syntax - they
863
894
  # require the order columns appear in the SELECT.
864
895
  #
865
896
  # columns_for_distinct("posts.id", ["posts.created_at desc"])
866
- def columns_for_distinct(columns, orders) #:nodoc:
897
+ #
898
+ def columns_for_distinct(columns, orders) # :nodoc:
867
899
  columns
868
900
  end
869
901
 
@@ -874,7 +906,7 @@ module ActiveRecord
874
906
  # add_timestamps(:suppliers, null: false)
875
907
  #
876
908
  def add_timestamps(table_name, options = {})
877
- emit_warning_if_null_unspecified(options)
909
+ emit_warning_if_null_unspecified(:add_timestamps, options)
878
910
  add_column table_name, :created_at, :datetime, options
879
911
  add_column table_name, :updated_at, :datetime, options
880
912
  end
@@ -55,11 +55,7 @@ module ActiveRecord
55
55
  end
56
56
 
57
57
  def add_record(record)
58
- if record.has_transactional_callbacks?
59
- records << record
60
- else
61
- record.set_transaction_state(@state)
62
- end
58
+ records << record
63
59
  end
64
60
 
65
61
  def rollback
@@ -111,6 +111,18 @@ module ActiveRecord
111
111
  @prepared_statements = false
112
112
  end
113
113
 
114
+ class Version
115
+ include Comparable
116
+
117
+ def initialize(version_string)
118
+ @version = version_string.split('.').map(&:to_i)
119
+ end
120
+
121
+ def <=>(version_string)
122
+ @version <=> version_string.split('.').map(&:to_i)
123
+ end
124
+ end
125
+
114
126
  class BindCollector < Arel::Collectors::Bind
115
127
  def compile(bvs, conn)
116
128
  super(bvs.map { |bv| conn.quote(*bv.reverse) })
@@ -457,7 +469,6 @@ module ActiveRecord
457
469
  message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
458
470
  end
459
471
 
460
- @logger.error message if @logger
461
472
  exception = translate_exception(e, message)
462
473
  exception.set_backtrace e.backtrace
463
474
  exception