activerecord 4.0.4 → 4.1.16

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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1632 -1797
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/examples/performance.rb +30 -18
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +4 -0
  9. data/lib/active_record/associations/alias_tracker.rb +49 -29
  10. data/lib/active_record/associations/association.rb +9 -17
  11. data/lib/active_record/associations/association_scope.rb +59 -49
  12. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
  14. data/lib/active_record/associations/builder/association.rb +84 -54
  15. data/lib/active_record/associations/builder/belongs_to.rb +90 -58
  16. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
  18. data/lib/active_record/associations/builder/has_many.rb +3 -3
  19. data/lib/active_record/associations/builder/has_one.rb +5 -7
  20. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  21. data/lib/active_record/associations/collection_association.rb +121 -111
  22. data/lib/active_record/associations/collection_proxy.rb +73 -18
  23. data/lib/active_record/associations/has_many_association.rb +14 -11
  24. data/lib/active_record/associations/has_many_through_association.rb +33 -6
  25. data/lib/active_record/associations/has_one_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
  27. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  28. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  29. data/lib/active_record/associations/join_dependency.rb +208 -168
  30. data/lib/active_record/associations/preloader/association.rb +69 -27
  31. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  35. data/lib/active_record/associations/preloader.rb +63 -49
  36. data/lib/active_record/associations/singular_association.rb +6 -5
  37. data/lib/active_record/associations/through_association.rb +30 -9
  38. data/lib/active_record/associations.rb +116 -42
  39. data/lib/active_record/attribute_assignment.rb +6 -3
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  41. data/lib/active_record/attribute_methods/dirty.rb +35 -26
  42. data/lib/active_record/attribute_methods/primary_key.rb +8 -1
  43. data/lib/active_record/attribute_methods/read.rb +56 -29
  44. data/lib/active_record/attribute_methods/serialization.rb +44 -12
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
  46. data/lib/active_record/attribute_methods/write.rb +59 -26
  47. data/lib/active_record/attribute_methods.rb +82 -43
  48. data/lib/active_record/autosave_association.rb +209 -194
  49. data/lib/active_record/base.rb +6 -2
  50. data/lib/active_record/callbacks.rb +2 -2
  51. data/lib/active_record/coders/json.rb +13 -0
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
  76. data/lib/active_record/connection_handling.rb +39 -5
  77. data/lib/active_record/core.rb +38 -54
  78. data/lib/active_record/counter_cache.rb +9 -10
  79. data/lib/active_record/dynamic_matchers.rb +6 -2
  80. data/lib/active_record/enum.rb +199 -0
  81. data/lib/active_record/errors.rb +22 -5
  82. data/lib/active_record/fixture_set/file.rb +2 -1
  83. data/lib/active_record/fixtures.rb +173 -76
  84. data/lib/active_record/gem_version.rb +15 -0
  85. data/lib/active_record/inheritance.rb +23 -9
  86. data/lib/active_record/integration.rb +54 -1
  87. data/lib/active_record/locking/optimistic.rb +7 -2
  88. data/lib/active_record/locking/pessimistic.rb +1 -1
  89. data/lib/active_record/log_subscriber.rb +6 -13
  90. data/lib/active_record/migration/command_recorder.rb +8 -2
  91. data/lib/active_record/migration.rb +91 -56
  92. data/lib/active_record/model_schema.rb +7 -14
  93. data/lib/active_record/nested_attributes.rb +25 -13
  94. data/lib/active_record/no_touching.rb +52 -0
  95. data/lib/active_record/null_relation.rb +26 -6
  96. data/lib/active_record/persistence.rb +23 -29
  97. data/lib/active_record/querying.rb +15 -12
  98. data/lib/active_record/railtie.rb +12 -61
  99. data/lib/active_record/railties/databases.rake +37 -56
  100. data/lib/active_record/readonly_attributes.rb +0 -6
  101. data/lib/active_record/reflection.rb +230 -79
  102. data/lib/active_record/relation/batches.rb +74 -24
  103. data/lib/active_record/relation/calculations.rb +52 -48
  104. data/lib/active_record/relation/delegation.rb +54 -39
  105. data/lib/active_record/relation/finder_methods.rb +210 -67
  106. data/lib/active_record/relation/merger.rb +15 -12
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
  109. data/lib/active_record/relation/predicate_builder.rb +81 -40
  110. data/lib/active_record/relation/query_methods.rb +185 -108
  111. data/lib/active_record/relation/spawn_methods.rb +8 -5
  112. data/lib/active_record/relation.rb +79 -84
  113. data/lib/active_record/result.rb +45 -6
  114. data/lib/active_record/runtime_registry.rb +5 -0
  115. data/lib/active_record/sanitization.rb +4 -4
  116. data/lib/active_record/schema_dumper.rb +18 -6
  117. data/lib/active_record/schema_migration.rb +31 -18
  118. data/lib/active_record/scoping/default.rb +5 -18
  119. data/lib/active_record/scoping/named.rb +14 -29
  120. data/lib/active_record/scoping.rb +5 -0
  121. data/lib/active_record/store.rb +67 -18
  122. data/lib/active_record/tasks/database_tasks.rb +66 -26
  123. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
  124. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  125. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  126. data/lib/active_record/timestamp.rb +6 -6
  127. data/lib/active_record/transactions.rb +10 -12
  128. data/lib/active_record/validations/presence.rb +1 -1
  129. data/lib/active_record/validations/uniqueness.rb +19 -9
  130. data/lib/active_record/version.rb +4 -7
  131. data/lib/active_record.rb +5 -7
  132. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  133. data/lib/rails/generators/active_record/migration.rb +18 -0
  134. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  135. data/lib/rails/generators/active_record.rb +2 -8
  136. metadata +18 -30
  137. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  138. data/lib/active_record/associations/join_helper.rb +0 -45
  139. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  140. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  141. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  142. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  143. data/lib/active_record/test_case.rb +0 -96
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
 
8
8
  MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
9
9
  :order, :joins, :where, :having, :bind, :references,
10
- :extending]
10
+ :extending, :unscope]
11
11
 
12
12
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
13
13
  :reverse_order, :distinct, :create_with, :uniq]
@@ -17,18 +17,15 @@ module ActiveRecord
17
17
  include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
18
18
 
19
19
  attr_reader :table, :klass, :loaded
20
- attr_accessor :default_scoped
21
20
  alias :model :klass
22
21
  alias :loaded? :loaded
23
- alias :default_scoped? :default_scoped
24
22
 
25
23
  def initialize(klass, table, values = {})
26
- @klass = klass
27
- @table = table
28
- @values = values
29
- @implicit_readonly = nil
30
- @loaded = false
31
- @default_scoped = false
24
+ @klass = klass
25
+ @table = table
26
+ @values = values
27
+ @offsets = {}
28
+ @loaded = false
32
29
  end
33
30
 
34
31
  def initialize_copy(other)
@@ -39,7 +36,7 @@ module ActiveRecord
39
36
  reset
40
37
  end
41
38
 
42
- def insert(values)
39
+ def insert(values) # :nodoc:
43
40
  primary_key_value = nil
44
41
 
45
42
  if primary_key && Hash === values
@@ -56,16 +53,7 @@ module ActiveRecord
56
53
  im = arel.create_insert
57
54
  im.into @table
58
55
 
59
- conn = @klass.connection
60
-
61
- substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
62
- binds = substitutes.map do |arel_attr, value|
63
- [@klass.columns_hash[arel_attr.name], value]
64
- end
65
-
66
- substitutes.each_with_index do |tuple, i|
67
- tuple[1] = conn.substitute_at(binds[i][0], i)
68
- end
56
+ substitutes, binds = substitute_values values
69
57
 
70
58
  if values.empty? # empty insert
71
59
  im.values = Arel.sql(connection.empty_insert_statement_value)
@@ -73,7 +61,7 @@ module ActiveRecord
73
61
  im.insert substitutes
74
62
  end
75
63
 
76
- conn.insert(
64
+ @klass.connection.insert(
77
65
  im,
78
66
  'SQL',
79
67
  primary_key,
@@ -82,6 +70,36 @@ module ActiveRecord
82
70
  binds)
83
71
  end
84
72
 
73
+ def _update_record(values, id, id_was) # :nodoc:
74
+ substitutes, binds = substitute_values values
75
+
76
+ scope = @klass.unscoped
77
+
78
+ if @klass.finder_needs_type_condition?
79
+ scope.unscope!(where: @klass.inheritance_column)
80
+ end
81
+
82
+ um = scope.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes, @klass.primary_key)
83
+
84
+ @klass.connection.update(
85
+ um,
86
+ 'SQL',
87
+ binds)
88
+ end
89
+
90
+ def substitute_values(values) # :nodoc:
91
+ substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
92
+ binds = substitutes.map do |arel_attr, value|
93
+ [@klass.columns_hash[arel_attr.name], value]
94
+ end
95
+
96
+ substitutes.each_with_index do |tuple, i|
97
+ tuple[1] = @klass.connection.substitute_at(binds[i][0], i)
98
+ end
99
+
100
+ [substitutes, binds]
101
+ end
102
+
85
103
  # Initializes new record from relation while maintaining the current
86
104
  # scope.
87
105
  #
@@ -227,15 +245,19 @@ module ActiveRecord
227
245
 
228
246
  # Returns size of the records.
229
247
  def size
230
- loaded? ? @records.length : count
248
+ loaded? ? @records.length : count(:all)
231
249
  end
232
250
 
233
251
  # Returns true if there are no records.
234
252
  def empty?
235
253
  return @records.empty? if loaded?
236
254
 
237
- c = count
238
- c.respond_to?(:zero?) ? c.zero? : c.empty?
255
+ if limit_value == 0
256
+ true
257
+ else
258
+ c = count(:all)
259
+ c.respond_to?(:zero?) ? c.zero? : c.empty?
260
+ end
239
261
  end
240
262
 
241
263
  # Returns true if there are any records.
@@ -300,7 +322,7 @@ module ActiveRecord
300
322
  stmt.table(table)
301
323
  stmt.key = table[primary_key]
302
324
 
303
- if with_default_scope.joins_values.any?
325
+ if joins_values.any?
304
326
  @klass.connection.join_to_update(stmt, arel)
305
327
  else
306
328
  stmt.take(arel.limit)
@@ -425,7 +447,7 @@ module ActiveRecord
425
447
  stmt = Arel::DeleteManager.new(arel.engine)
426
448
  stmt.from(table)
427
449
 
428
- if with_default_scope.joins_values.any?
450
+ if joins_values.any?
429
451
  @klass.connection.join_to_delete(stmt, arel, table[primary_key])
430
452
  else
431
453
  stmt.wheres = arel.constraints
@@ -480,9 +502,10 @@ module ActiveRecord
480
502
  end
481
503
 
482
504
  def reset
483
- @first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
505
+ @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
484
506
  @should_eager_load = @join_dependency = nil
485
507
  @records = []
508
+ @offsets = {}
486
509
  self
487
510
  end
488
511
 
@@ -491,16 +514,30 @@ module ActiveRecord
491
514
  # User.where(name: 'Oscar').to_sql
492
515
  # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
493
516
  def to_sql
494
- @to_sql ||= klass.connection.to_sql(arel, bind_values.dup)
517
+ @to_sql ||= begin
518
+ relation = self
519
+ connection = klass.connection
520
+ visitor = connection.visitor
521
+
522
+ if eager_loading?
523
+ find_with_associations { |rel| relation = rel }
524
+ end
525
+
526
+ ast = relation.arel.ast
527
+ binds = relation.bind_values.dup
528
+ visitor.accept(ast) do
529
+ connection.quote(*binds.shift.reverse)
530
+ end
531
+ end
495
532
  end
496
533
 
497
534
  # Returns a hash of where conditions.
498
535
  #
499
536
  # User.where(name: 'Oscar').where_values_hash
500
537
  # # => {name: "Oscar"}
501
- def where_values_hash
502
- equalities = with_default_scope.where_values.grep(Arel::Nodes::Equality).find_all { |node|
503
- node.left.relation.name == table_name
538
+ def where_values_hash(relation_table_name = table_name)
539
+ equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
540
+ node.left.relation.name == relation_table_name
504
541
  }
505
542
 
506
543
  binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
@@ -539,6 +576,8 @@ module ActiveRecord
539
576
  # Compares two relations for equality.
540
577
  def ==(other)
541
578
  case other
579
+ when Associations::CollectionProxy, AssociationRelation
580
+ self == other.to_a
542
581
  when Relation
543
582
  other.to_sql == to_sql
544
583
  when Array
@@ -550,16 +589,6 @@ module ActiveRecord
550
589
  q.pp(self.to_a)
551
590
  end
552
591
 
553
- def with_default_scope #:nodoc:
554
- if default_scoped? && default_scope = klass.send(:build_default_scope)
555
- default_scope = default_scope.merge(self)
556
- default_scope.default_scoped = false
557
- default_scope
558
- else
559
- self
560
- end
561
- end
562
-
563
592
  # Returns true if relation is blank.
564
593
  def blank?
565
594
  to_a.blank?
@@ -579,25 +608,17 @@ module ActiveRecord
579
608
  private
580
609
 
581
610
  def exec_queries
582
- default_scoped = with_default_scope
583
-
584
- if default_scoped.equal?(self)
585
- @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
611
+ @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
586
612
 
587
- preload = preload_values
588
- preload += includes_values unless eager_loading?
589
- preload.each do |associations|
590
- ActiveRecord::Associations::Preloader.new(@records, associations).run
591
- end
592
-
593
- # @readonly_value is true only if set explicitly. @implicit_readonly is true if there
594
- # are JOINS and no explicit SELECT.
595
- readonly = readonly_value.nil? ? @implicit_readonly : readonly_value
596
- @records.each { |record| record.readonly! } if readonly
597
- else
598
- @records = default_scoped.to_a
613
+ preload = preload_values
614
+ preload += includes_values unless eager_loading?
615
+ preloader = ActiveRecord::Associations::Preloader.new
616
+ preload.each do |associations|
617
+ preloader.preload @records, associations
599
618
  end
600
619
 
620
+ @records.each { |record| record.readonly! } if readonly_value
621
+
601
622
  @loaded = true
602
623
  @records
603
624
  end
@@ -615,34 +636,8 @@ module ActiveRecord
615
636
 
616
637
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
617
638
  joined_tables = joined_tables.flatten.compact.map { |t| t.downcase }.uniq
618
- string_tables = tables_in_string(to_sql)
619
639
 
620
- if (references_values - joined_tables).any?
621
- true
622
- elsif !ActiveRecord::Base.disable_implicit_join_references &&
623
- (string_tables - joined_tables).any?
624
- ActiveSupport::Deprecation.warn(
625
- "It looks like you are eager loading table(s) (one of: #{string_tables.join(', ')}) " \
626
- "that are referenced in a string SQL snippet. For example: \n" \
627
- "\n" \
628
- " Post.includes(:comments).where(\"comments.title = 'foo'\")\n" \
629
- "\n" \
630
- "Currently, Active Record recognizes the table in the string, and knows to JOIN the " \
631
- "comments table to the query, rather than loading comments in a separate query. " \
632
- "However, doing this without writing a full-blown SQL parser is inherently flawed. " \
633
- "Since we don't want to write an SQL parser, we are removing this functionality. " \
634
- "From now on, you must explicitly tell Active Record when you are referencing a table " \
635
- "from a string:\n" \
636
- "\n" \
637
- " Post.includes(:comments).where(\"comments.title = 'foo'\").references(:comments)\n" \
638
- "\n" \
639
- "If you don't rely on implicit join references you can disable the feature entirely " \
640
- "by setting `config.active_record.disable_implicit_join_references = true`."
641
- )
642
- true
643
- else
644
- false
645
- end
640
+ (references_values - joined_tables).any?
646
641
  end
647
642
 
648
643
  def tables_in_string(string)
@@ -3,11 +3,36 @@ module ActiveRecord
3
3
  # This class encapsulates a Result returned from calling +exec_query+ on any
4
4
  # database connection adapter. For example:
5
5
  #
6
- # x = ActiveRecord::Base.connection.exec_query('SELECT * FROM foo')
7
- # x # => #<ActiveRecord::Result:0xdeadbeef>
6
+ # result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
7
+ # result # => #<ActiveRecord::Result:0xdeadbeef>
8
+ #
9
+ # # Get the column names of the result:
10
+ # result.columns
11
+ # # => ["id", "title", "body"]
12
+ #
13
+ # # Get the record values of the result:
14
+ # result.rows
15
+ # # => [[1, "title_1", "body_1"],
16
+ # [2, "title_2", "body_2"],
17
+ # ...
18
+ # ]
19
+ #
20
+ # # Get an array of hashes representing the result (column => value):
21
+ # result.to_hash
22
+ # # => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
23
+ # {"id" => 2, "title" => "title_2", "body" => "body_2"},
24
+ # ...
25
+ # ]
26
+ #
27
+ # # ActiveRecord::Result also includes Enumerable.
28
+ # result.each do |row|
29
+ # puts row['title'] + " " + row['body']
30
+ # end
8
31
  class Result
9
32
  include Enumerable
10
33
 
34
+ IDENTITY_TYPE = Class.new { def type_cast(v); v; end }.new # :nodoc:
35
+
11
36
  attr_reader :columns, :rows, :column_types
12
37
 
13
38
  def initialize(columns, rows, column_types = {})
@@ -17,8 +42,20 @@ module ActiveRecord
17
42
  @column_types = column_types
18
43
  end
19
44
 
45
+ def identity_type # :nodoc:
46
+ IDENTITY_TYPE
47
+ end
48
+
49
+ def column_type(name)
50
+ @column_types[name] || identity_type
51
+ end
52
+
20
53
  def each
21
- hash_rows.each { |row| yield row }
54
+ if block_given?
55
+ hash_rows.each { |row| yield row }
56
+ else
57
+ hash_rows.to_enum { @rows.size }
58
+ end
22
59
  end
23
60
 
24
61
  def to_hash
@@ -46,12 +83,14 @@ module ActiveRecord
46
83
  end
47
84
 
48
85
  def initialize_copy(other)
49
- @columns = columns.dup
50
- @rows = rows.dup
51
- @hash_rows = nil
86
+ @columns = columns.dup
87
+ @rows = rows.dup
88
+ @column_types = column_types.dup
89
+ @hash_rows = nil
52
90
  end
53
91
 
54
92
  private
93
+
55
94
  def hash_rows
56
95
  @hash_rows ||=
57
96
  begin
@@ -13,5 +13,10 @@ module ActiveRecord
13
13
  extend ActiveSupport::PerThreadRegistry
14
14
 
15
15
  attr_accessor :connection_handler, :sql_runtime, :connection_id
16
+
17
+ [:connection_handler, :sql_runtime, :connection_id].each do |val|
18
+ class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
19
+ class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
20
+ end
16
21
  end
17
22
  end
@@ -3,8 +3,8 @@ module ActiveRecord
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  module ClassMethods
6
- def quote_value(value, column = nil) #:nodoc:
7
- connection.quote(value,column)
6
+ def quote_value(value, column) #:nodoc:
7
+ connection.quote(value, column)
8
8
  end
9
9
 
10
10
  # Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
@@ -29,6 +29,7 @@ module ActiveRecord
29
29
  end
30
30
  end
31
31
  alias_method :sanitize_sql, :sanitize_sql_for_conditions
32
+ alias_method :sanitize_conditions, :sanitize_sql
32
33
 
33
34
  # Accepts an array, hash, or string of SQL conditions and sanitizes
34
35
  # them into a valid SQL fragment for a SET clause.
@@ -86,6 +87,7 @@ module ActiveRecord
86
87
  # { address: Address.new("123 abc st.", "chicago") }
87
88
  # # => "address_street='123 abc st.' and address_city='chicago'"
88
89
  def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
90
+ attrs = PredicateBuilder.resolve_column_aliases self, attrs
89
91
  attrs = expand_hash_conditions_for_aggregates(attrs)
90
92
 
91
93
  table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
@@ -121,8 +123,6 @@ module ActiveRecord
121
123
  end
122
124
  end
123
125
 
124
- alias_method :sanitize_conditions, :sanitize_sql
125
-
126
126
  def replace_bind_variables(statement, values) #:nodoc:
127
127
  raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
128
128
  bound = values.dup
@@ -17,9 +17,19 @@ module ActiveRecord
17
17
  cattr_accessor :ignore_tables
18
18
  @@ignore_tables = []
19
19
 
20
- def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
21
- new(connection).dump(stream)
22
- stream
20
+ class << self
21
+ def dump(connection=ActiveRecord::Base.connection, stream=STDOUT, config = ActiveRecord::Base)
22
+ new(connection, generate_options(config)).dump(stream)
23
+ stream
24
+ end
25
+
26
+ private
27
+ def generate_options(config)
28
+ {
29
+ table_name_prefix: config.table_name_prefix,
30
+ table_name_suffix: config.table_name_suffix
31
+ }
32
+ end
23
33
  end
24
34
 
25
35
  def dump(stream)
@@ -32,10 +42,11 @@ module ActiveRecord
32
42
 
33
43
  private
34
44
 
35
- def initialize(connection)
45
+ def initialize(connection, options = {})
36
46
  @connection = connection
37
47
  @types = @connection.native_database_types
38
48
  @version = Migrator::current_version rescue nil
49
+ @options = options
39
50
  end
40
51
 
41
52
  def header(stream)
@@ -101,7 +112,8 @@ HEADER
101
112
  # first dump primary key column
102
113
  if @connection.respond_to?(:pk_and_sequence_for)
103
114
  pk, _ = @connection.pk_and_sequence_for(table)
104
- elsif @connection.respond_to?(:primary_key)
115
+ end
116
+ if !pk && @connection.respond_to?(:primary_key)
105
117
  pk = @connection.primary_key(table)
106
118
  end
107
119
 
@@ -202,7 +214,7 @@ HEADER
202
214
  end
203
215
 
204
216
  def remove_prefix_and_suffix(table)
205
- table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
217
+ table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
206
218
  end
207
219
  end
208
220
  end
@@ -4,31 +4,44 @@ require 'active_record/base'
4
4
 
5
5
  module ActiveRecord
6
6
  class SchemaMigration < ActiveRecord::Base
7
+ class << self
8
+ def primary_key
9
+ nil
10
+ end
7
11
 
8
- def self.table_name
9
- "#{Base.table_name_prefix}schema_migrations#{Base.table_name_suffix}"
10
- end
12
+ def table_name
13
+ "#{table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
14
+ end
11
15
 
12
- def self.index_name
13
- "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
14
- end
16
+ def index_name
17
+ "#{table_name_prefix}unique_#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
18
+ end
15
19
 
16
- def self.create_table(limit=nil)
17
- unless connection.table_exists?(table_name)
18
- version_options = {null: false}
19
- version_options[:limit] = limit if limit
20
+ def table_exists?
21
+ connection.table_exists?(table_name)
22
+ end
20
23
 
21
- connection.create_table(table_name, id: false) do |t|
22
- t.column :version, :string, version_options
24
+ def create_table(limit=nil)
25
+ unless table_exists?
26
+ version_options = {null: false}
27
+ version_options[:limit] = limit if limit
28
+
29
+ connection.create_table(table_name, id: false) do |t|
30
+ t.column :version, :string, version_options
31
+ end
32
+ connection.add_index table_name, :version, unique: true, name: index_name
33
+ end
34
+ end
35
+
36
+ def drop_table
37
+ if table_exists?
38
+ connection.remove_index table_name, name: index_name
39
+ connection.drop_table(table_name)
23
40
  end
24
- connection.add_index table_name, :version, unique: true, name: index_name
25
41
  end
26
- end
27
42
 
28
- def self.drop_table
29
- if connection.table_exists?(table_name)
30
- connection.remove_index table_name, name: index_name
31
- connection.drop_table(table_name)
43
+ def normalize_migration_number(number)
44
+ "%.3d" % number.to_i
32
45
  end
33
46
  end
34
47
 
@@ -8,14 +8,6 @@ module ActiveRecord
8
8
  class_attribute :default_scopes, instance_writer: false, instance_predicate: false
9
9
 
10
10
  self.default_scopes = []
11
-
12
- def self.default_scopes?
13
- ActiveSupport::Deprecation.warn(
14
- "#default_scopes? is deprecated. Do something like #default_scopes.empty? instead."
15
- )
16
-
17
- !!self.default_scopes
18
- end
19
11
  end
20
12
 
21
13
  module ClassMethods
@@ -91,29 +83,24 @@ module ActiveRecord
91
83
  scope = Proc.new if block_given?
92
84
 
93
85
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
94
- ActiveSupport::Deprecation.warn(
95
- "Calling #default_scope without a block is deprecated. For example instead " \
86
+ raise ArgumentError,
87
+ "Support for calling #default_scope without a block is removed. For example instead " \
96
88
  "of `default_scope where(color: 'red')`, please use " \
97
89
  "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
98
90
  "self.default_scope.)"
99
- )
100
91
  end
101
92
 
102
93
  self.default_scopes += [scope]
103
94
  end
104
95
 
105
- def build_default_scope # :nodoc:
96
+ def build_default_scope(base_rel = relation) # :nodoc:
106
97
  if !Base.is_a?(method(:default_scope).owner)
107
98
  # The user has defined their own default scope method, so call that
108
99
  evaluate_default_scope { default_scope }
109
100
  elsif default_scopes.any?
110
101
  evaluate_default_scope do
111
- default_scopes.inject(relation) do |default_scope, scope|
112
- if !scope.is_a?(Relation) && scope.respond_to?(:call)
113
- default_scope.merge(unscoped { scope.call })
114
- else
115
- default_scope.merge(scope)
116
- end
102
+ default_scopes.inject(base_rel) do |default_scope, scope|
103
+ default_scope.merge(base_rel.scoping { scope.call })
117
104
  end
118
105
  end
119
106
  end
@@ -25,22 +25,18 @@ module ActiveRecord
25
25
  if current_scope
26
26
  current_scope.clone
27
27
  else
28
- scope = relation
29
- scope.default_scoped = true
30
- scope
28
+ default_scoped
31
29
  end
32
30
  end
33
31
 
32
+ def default_scoped # :nodoc:
33
+ relation.merge(build_default_scope)
34
+ end
35
+
34
36
  # Collects attributes from scopes that should be applied when creating
35
37
  # an AR instance for the particular class this is called on.
36
38
  def scope_attributes # :nodoc:
37
- if current_scope
38
- current_scope.scope_for_create
39
- else
40
- scope = relation
41
- scope.default_scoped = true
42
- scope.scope_for_create
43
- end
39
+ all.scope_for_create
44
40
  end
45
41
 
46
42
  # Are there default attributes associated with this scope?
@@ -143,28 +139,17 @@ module ActiveRecord
143
139
  # Article.published.featured.latest_article
144
140
  # Article.featured.titles
145
141
  def scope(name, body, &block)
146
- extension = Module.new(&block) if block
147
-
148
- # Check body.is_a?(Relation) to prevent the relation actually being
149
- # loaded by respond_to?
150
- if body.is_a?(Relation) || !body.respond_to?(:call)
151
- ActiveSupport::Deprecation.warn(
152
- "Using #scope without passing a callable object is deprecated. For " \
153
- "example `scope :red, where(color: 'red')` should be changed to " \
154
- "`scope :red, -> { where(color: 'red') }`. There are numerous gotchas " \
155
- "in the former usage and it makes the implementation more complicated " \
156
- "and buggy. (If you prefer, you can just define a class method named " \
157
- "`self.red`.)"
158
- )
142
+ if dangerous_class_method?(name)
143
+ raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
144
+ "on the model \"#{self.name}\", but Active Record already defined " \
145
+ "a class method with the same name."
159
146
  end
160
147
 
148
+ extension = Module.new(&block) if block
149
+
161
150
  singleton_class.send(:define_method, name) do |*args|
162
- if body.respond_to?(:call)
163
- scope = all.scoping { body.call(*args) }
164
- scope = scope.extending(extension) if extension
165
- else
166
- scope = body
167
- end
151
+ scope = all.scoping { body.call(*args) }
152
+ scope = scope.extending(extension) if extension
168
153
 
169
154
  scope || all
170
155
  end
@@ -27,6 +27,11 @@ module ActiveRecord
27
27
  end
28
28
  end
29
29
 
30
+ def initialize_internals_callback
31
+ super
32
+ populate_with_current_scope_attributes
33
+ end
34
+
30
35
  # This class stores the +:current_scope+ and +:ignore_default_scope+ values
31
36
  # for different classes. The registry is stored as a thread local, which is
32
37
  # accessed through +ScopeRegistry.current+.