activerecord 4.2.11.3 → 5.0.0.beta1

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 (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. data/lib/active_record/type/value.rb +0 -110
@@ -3,36 +3,53 @@ module ActiveRecord
3
3
  class StatementPool
4
4
  include Enumerable
5
5
 
6
- def initialize(connection, max = 1000)
7
- @connection = connection
8
- @max = max
6
+ def initialize(max = 1000)
7
+ @cache = Hash.new { |h,pid| h[pid] = {} }
8
+ @max = max
9
9
  end
10
10
 
11
- def each
12
- raise NotImplementedError
11
+ def each(&block)
12
+ cache.each(&block)
13
13
  end
14
14
 
15
15
  def key?(key)
16
- raise NotImplementedError
16
+ cache.key?(key)
17
17
  end
18
18
 
19
19
  def [](key)
20
- raise NotImplementedError
20
+ cache[key]
21
21
  end
22
22
 
23
23
  def length
24
- raise NotImplementedError
24
+ cache.length
25
25
  end
26
26
 
27
- def []=(sql, key)
28
- raise NotImplementedError
27
+ def []=(sql, stmt)
28
+ while @max <= cache.size
29
+ dealloc(cache.shift.last)
30
+ end
31
+ cache[sql] = stmt
29
32
  end
30
33
 
31
34
  def clear
32
- raise NotImplementedError
35
+ cache.each_value do |stmt|
36
+ dealloc stmt
37
+ end
38
+ cache.clear
33
39
  end
34
40
 
35
41
  def delete(key)
42
+ dealloc cache[key]
43
+ cache.delete(key)
44
+ end
45
+
46
+ private
47
+
48
+ def cache
49
+ @cache[Process.pid]
50
+ end
51
+
52
+ def dealloc(stmt)
36
53
  raise NotImplementedError
37
54
  end
38
55
  end
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
 
6
6
  # Establishes the connection to the database. Accepts a hash as input where
7
7
  # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
8
- # example for regular databases (MySQL, Postgresql, etc):
8
+ # example for regular databases (MySQL, PostgreSQL, etc):
9
9
  #
10
10
  # ActiveRecord::Base.establish_connection(
11
11
  # adapter: "mysql",
@@ -35,14 +35,14 @@ module ActiveRecord
35
35
  # "postgres://myuser:mypass@localhost/somedatabase"
36
36
  # )
37
37
  #
38
- # In case <tt>ActiveRecord::Base.configurations</tt> is set (Rails
39
- # automatically loads the contents of config/database.yml into it),
38
+ # In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
39
+ # is set (Rails automatically loads the contents of config/database.yml into it),
40
40
  # a symbol can also be given as argument, representing a key in the
41
41
  # configuration hash:
42
42
  #
43
43
  # ActiveRecord::Base.establish_connection(:production)
44
44
  #
45
- # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
45
+ # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
46
46
  # may be returned on an error.
47
47
  def establish_connection(spec = nil)
48
48
  spec ||= DEFAULT_ENV.call.to_sym
@@ -88,7 +88,7 @@ module ActiveRecord
88
88
  end
89
89
 
90
90
  def connection_id
91
- ActiveRecord::RuntimeRegistry.connection_id
91
+ ActiveRecord::RuntimeRegistry.connection_id ||= Thread.current.object_id
92
92
  end
93
93
 
94
94
  def connection_id=(connection_id)
@@ -85,17 +85,30 @@ module ActiveRecord
85
85
  mattr_accessor :dump_schema_after_migration, instance_writer: false
86
86
  self.dump_schema_after_migration = true
87
87
 
88
+ ##
89
+ # :singleton-method:
90
+ # Specifies which database schemas to dump when calling db:structure:dump.
91
+ # If the value is :schema_search_path (the default), any schemas listed in
92
+ # schema_search_path are dumped. Use :all to dump all schemas regardless
93
+ # of schema_search_path, or a string of comma separated schemas for a
94
+ # custom list.
95
+ mattr_accessor :dump_schemas, instance_writer: false
96
+ self.dump_schemas = :schema_search_path
97
+
98
+ ##
99
+ # :singleton-method:
100
+ # Specify a threshold for the size of query result sets. If the number of
101
+ # records in the set exceeds the threshold, a warning is logged. This can
102
+ # be used to identify queries which load thousands of records and
103
+ # potentially cause memory bloat.
104
+ mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
105
+ self.warn_on_records_fetched_greater_than = nil
106
+
88
107
  mattr_accessor :maintain_test_schema, instance_accessor: false
89
108
 
90
- def self.disable_implicit_join_references=(value)
91
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
92
- Implicit join references were removed with Rails 4.1.
93
- Make sure to remove this configuration because it does nothing.
94
- MSG
95
- end
109
+ mattr_accessor :belongs_to_required_by_default, instance_accessor: false
96
110
 
97
111
  class_attribute :default_connection_handler, instance_writer: false
98
- class_attribute :find_by_statement_cache
99
112
 
100
113
  def self.connection_handler
101
114
  ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
@@ -115,10 +128,11 @@ module ActiveRecord
115
128
  end
116
129
 
117
130
  def initialize_find_by_cache # :nodoc:
118
- self.find_by_statement_cache = {}.extend(Mutex_m)
131
+ @find_by_statement_cache = {}.extend(Mutex_m)
119
132
  end
120
133
 
121
134
  def inherited(child_class) # :nodoc:
135
+ # initialize cache at class definition for thread safety
122
136
  child_class.initialize_find_by_cache
123
137
  super
124
138
  end
@@ -126,12 +140,9 @@ module ActiveRecord
126
140
  def find(*ids) # :nodoc:
127
141
  # We don't have cache keys for this stuff yet
128
142
  return super unless ids.length == 1
129
- # Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
130
- return super if ids.first.kind_of?(Symbol)
131
143
  return super if block_given? ||
132
144
  primary_key.nil? ||
133
- default_scopes.any? ||
134
- current_scope ||
145
+ scope_attributes? ||
135
146
  columns_hash.include?(inheritance_column) ||
136
147
  ids.first.kind_of?(Array)
137
148
 
@@ -143,57 +154,54 @@ module ActiveRecord
143
154
  Please pass the id of the object by calling `.id`
144
155
  MSG
145
156
  end
157
+
146
158
  key = primary_key
147
159
 
148
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
149
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
150
- where(key => params.bind).limit(1)
151
- }
160
+ statement = cached_find_by_statement(key) { |params|
161
+ where(key => params.bind).limit(1)
152
162
  }
153
- record = s.execute([id], self, connection).first
163
+ record = statement.execute([id], self, connection).first
154
164
  unless record
155
- raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
165
+ raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
166
+ name, primary_key, id)
156
167
  end
157
168
  record
158
169
  rescue RangeError
159
- raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
170
+ raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
171
+ name, primary_key)
160
172
  end
161
173
 
162
174
  def find_by(*args) # :nodoc:
163
- return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
164
- return super if default_scopes.any?
175
+ return super if scope_attributes? || !(Hash === args.first) || reflect_on_all_aggregations.any?
165
176
 
166
177
  hash = args.first
167
178
 
168
179
  return super if hash.values.any? { |v|
169
- v.nil? || Array === v || Hash === v
180
+ v.nil? || Array === v || Hash === v || Relation === v
170
181
  }
171
182
 
172
183
  # We can't cache Post.find_by(author: david) ...yet
173
184
  return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
174
185
 
175
- key = hash.keys
186
+ keys = hash.keys
176
187
 
177
- klass = self
178
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
179
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
180
- wheres = key.each_with_object({}) { |param,o|
181
- o[param] = params.bind
182
- }
183
- klass.where(wheres).limit(1)
188
+ statement = cached_find_by_statement(keys) { |params|
189
+ wheres = keys.each_with_object({}) { |param, o|
190
+ o[param] = params.bind
184
191
  }
192
+ where(wheres).limit(1)
185
193
  }
186
194
  begin
187
- s.execute(hash.values, self, connection).first
188
- rescue TypeError => e
189
- raise ActiveRecord::StatementInvalid.new(e.message, e)
195
+ statement.execute(hash.values, self, connection).first
196
+ rescue TypeError
197
+ raise ActiveRecord::StatementInvalid
190
198
  rescue RangeError
191
199
  nil
192
200
  end
193
201
  end
194
202
 
195
203
  def find_by!(*args) # :nodoc:
196
- find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
204
+ find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
197
205
  end
198
206
 
199
207
  def initialize_generated_modules # :nodoc:
@@ -217,7 +225,7 @@ module ActiveRecord
217
225
  elsif !connected?
218
226
  "#{super} (call '#{super}.connection' to establish a connection)"
219
227
  elsif table_exists?
220
- attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
228
+ attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
221
229
  "#{super}(#{attr_list})"
222
230
  else
223
231
  "#{super}(Table doesn't exist)"
@@ -235,7 +243,7 @@ module ActiveRecord
235
243
  # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
236
244
  # end
237
245
  def arel_table # :nodoc:
238
- @arel_table ||= Arel::Table.new(table_name, arel_engine)
246
+ @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
239
247
  end
240
248
 
241
249
  # Returns the Arel engine.
@@ -248,10 +256,24 @@ module ActiveRecord
248
256
  end
249
257
  end
250
258
 
259
+ def predicate_builder # :nodoc:
260
+ @predicate_builder ||= PredicateBuilder.new(table_metadata)
261
+ end
262
+
263
+ def type_caster # :nodoc:
264
+ TypeCaster::Map.new(self)
265
+ end
266
+
251
267
  private
252
268
 
253
- def relation #:nodoc:
254
- relation = Relation.create(self, arel_table)
269
+ def cached_find_by_statement(key, &block) # :nodoc:
270
+ @find_by_statement_cache[key] || @find_by_statement_cache.synchronize {
271
+ @find_by_statement_cache[key] ||= StatementCache.create(connection, &block)
272
+ }
273
+ end
274
+
275
+ def relation # :nodoc:
276
+ relation = Relation.create(self, arel_table, predicate_builder)
255
277
 
256
278
  if finder_needs_type_condition?
257
279
  relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
@@ -259,6 +281,10 @@ module ActiveRecord
259
281
  relation
260
282
  end
261
283
  end
284
+
285
+ def table_metadata # :nodoc:
286
+ TableMetadata.new(self, arel_table)
287
+ end
262
288
  end
263
289
 
264
290
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -269,16 +295,14 @@ module ActiveRecord
269
295
  # ==== Example:
270
296
  # # Instantiates a single new object
271
297
  # User.new(first_name: 'Jamie')
272
- def initialize(attributes = nil, options = {})
273
- @attributes = self.class._default_attributes.dup
298
+ def initialize(attributes = nil)
299
+ @attributes = self.class._default_attributes.deep_dup
274
300
  self.class.define_attribute_methods
275
301
 
276
302
  init_internals
277
303
  initialize_internals_callback
278
304
 
279
- # +options+ argument is only needed to make protected_attributes gem easier to hook.
280
- # Remove it when we drop support to this gem.
281
- init_attributes(attributes, options) if attributes
305
+ assign_attributes(attributes) if attributes
282
306
 
283
307
  yield self if block_given?
284
308
  _run_initialize_callbacks
@@ -286,7 +310,7 @@ module ActiveRecord
286
310
 
287
311
  # Initialize an empty model object from +coder+. +coder+ should be
288
312
  # the result of previously encoding an Active Record model, using
289
- # `encode_with`
313
+ # #encode_with.
290
314
  #
291
315
  # class Post < ActiveRecord::Base
292
316
  # end
@@ -342,14 +366,11 @@ module ActiveRecord
342
366
 
343
367
  ##
344
368
  def initialize_dup(other) # :nodoc:
345
- @attributes = @attributes.dup
369
+ @attributes = @attributes.deep_dup
346
370
  @attributes.reset(self.class.primary_key)
347
371
 
348
372
  _run_initialize_callbacks
349
373
 
350
- @aggregation_cache = {}
351
- @association_cache = {}
352
-
353
374
  @new_record = true
354
375
  @destroyed = false
355
376
 
@@ -358,7 +379,7 @@ module ActiveRecord
358
379
 
359
380
  # Populate +coder+ with attributes about this record that should be
360
381
  # serialized. The structure of +coder+ defined in this method is
361
- # guaranteed to match the structure of +coder+ passed to the +init_with+
382
+ # guaranteed to match the structure of +coder+ passed to the #init_with
362
383
  # method.
363
384
  #
364
385
  # Example:
@@ -373,7 +394,7 @@ module ActiveRecord
373
394
  coder['raw_attributes'] = attributes_before_type_cast
374
395
  coder['attributes'] = @attributes
375
396
  coder['new_record'] = new_record?
376
- coder['active_record_yaml_version'] = 0
397
+ coder['active_record_yaml_version'] = 1
377
398
  end
378
399
 
379
400
  # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
@@ -456,7 +477,7 @@ module ActiveRecord
456
477
  "#<#{self.class} #{inspection}>"
457
478
  end
458
479
 
459
- # Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record`
480
+ # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
460
481
  # when pp is required.
461
482
  def pretty_print(pp)
462
483
  return super if custom_inspect_method_defined?
@@ -487,51 +508,6 @@ module ActiveRecord
487
508
 
488
509
  private
489
510
 
490
- def set_transaction_state(state) # :nodoc:
491
- @transaction_state = state
492
- end
493
-
494
- def has_transactional_callbacks? # :nodoc:
495
- !_rollback_callbacks.empty? || !_commit_callbacks.empty?
496
- end
497
-
498
- # Updates the attributes on this particular ActiveRecord object so that
499
- # if it is associated with a transaction, then the state of the AR object
500
- # will be updated to reflect the current state of the transaction
501
- #
502
- # The @transaction_state variable stores the states of the associated
503
- # transaction. This relies on the fact that a transaction can only be in
504
- # one rollback or commit (otherwise a list of states would be required)
505
- # Each AR object inside of a transaction carries that transaction's
506
- # TransactionState.
507
- #
508
- # This method checks to see if the ActiveRecord object's state reflects
509
- # the TransactionState, and rolls back or commits the ActiveRecord object
510
- # as appropriate.
511
- #
512
- # Since ActiveRecord objects can be inside multiple transactions, this
513
- # method recursively goes through the parent of the TransactionState and
514
- # checks if the ActiveRecord object reflects the state of the object.
515
- def sync_with_transaction_state
516
- update_attributes_from_transaction_state(@transaction_state, 0)
517
- end
518
-
519
- def update_attributes_from_transaction_state(transaction_state, depth)
520
- @reflects_state = [false] if depth == 0
521
-
522
- if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
523
- unless @reflects_state[depth]
524
- restore_transaction_record_state if transaction_state.rolledback?
525
- clear_transaction_record_state
526
- @reflects_state[depth] = true
527
- end
528
-
529
- if transaction_state.parent && !@reflects_state[depth+1]
530
- update_attributes_from_transaction_state(transaction_state.parent, depth+1)
531
- end
532
- end
533
- end
534
-
535
511
  # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
536
512
  # of the array, and then rescues from the possible NoMethodError. If those elements are
537
513
  # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
@@ -545,8 +521,6 @@ module ActiveRecord
545
521
  end
546
522
 
547
523
  def init_internals
548
- @aggregation_cache = {}
549
- @association_cache = {}
550
524
  @readonly = false
551
525
  @destroyed = false
552
526
  @marked_for_destruction = false
@@ -560,12 +534,6 @@ module ActiveRecord
560
534
  def initialize_internals_callback
561
535
  end
562
536
 
563
- # This method is needed to make protected_attributes gem easier to hook.
564
- # Remove it when we drop support to this gem.
565
- def init_attributes(attributes, options)
566
- assign_attributes(attributes)
567
- end
568
-
569
537
  def thaw
570
538
  if frozen?
571
539
  @attributes = @attributes.dup
@@ -37,23 +37,22 @@ module ActiveRecord
37
37
  reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
38
38
  counter_name = reflection.counter_cache_column
39
39
 
40
- stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
41
- arel_table[counter_name] => object.send(counter_association).count(:all)
42
- }, primary_key)
43
- connection.update stmt
40
+ unscoped.where(primary_key => object.id).update_all(
41
+ counter_name => object.send(counter_association).count(:all)
42
+ )
44
43
  end
45
44
  return true
46
45
  end
47
46
 
48
47
  # A generic "counter updater" implementation, intended primarily to be
49
- # used by increment_counter and decrement_counter, but which may also
48
+ # used by #increment_counter and #decrement_counter, but which may also
50
49
  # be useful on its own. It simply does a direct SQL update for the record
51
50
  # with the given ID, altering the given hash of counters by the amount
52
51
  # given by the corresponding value:
53
52
  #
54
53
  # ==== Parameters
55
54
  #
56
- # * +id+ - The id of the object you wish to update a counter on or an Array of ids.
55
+ # * +id+ - The id of the object you wish to update a counter on or an array of ids.
57
56
  # * +counters+ - A Hash containing the names of the fields
58
57
  # to update as keys and the amount to update the field by as values.
59
58
  #
@@ -87,14 +86,14 @@ module ActiveRecord
87
86
  # Increment a numeric field by one, via a direct SQL update.
88
87
  #
89
88
  # This method is used primarily for maintaining counter_cache columns that are
90
- # used to store aggregate values. For example, a DiscussionBoard may cache
89
+ # used to store aggregate values. For example, a +DiscussionBoard+ may cache
91
90
  # posts_count and comments_count to avoid running an SQL query to calculate the
92
91
  # number of posts and comments there are, each time it is displayed.
93
92
  #
94
93
  # ==== Parameters
95
94
  #
96
95
  # * +counter_name+ - The name of the field that should be incremented.
97
- # * +id+ - The id of the object that should be incremented or an Array of ids.
96
+ # * +id+ - The id of the object that should be incremented or an array of ids.
98
97
  #
99
98
  # ==== Examples
100
99
  #
@@ -106,13 +105,13 @@ module ActiveRecord
106
105
 
107
106
  # Decrement a numeric field by one, via a direct SQL update.
108
107
  #
109
- # This works the same as increment_counter but reduces the column value by
108
+ # This works the same as #increment_counter but reduces the column value by
110
109
  # 1 instead of increasing it.
111
110
  #
112
111
  # ==== Parameters
113
112
  #
114
113
  # * +counter_name+ - The name of the field that should be decremented.
115
- # * +id+ - The id of the object that should be decremented or an Array of ids.
114
+ # * +id+ - The id of the object that should be decremented or an array of ids.
116
115
  #
117
116
  # ==== Examples
118
117
  #
@@ -123,16 +122,6 @@ module ActiveRecord
123
122
  end
124
123
  end
125
124
 
126
- protected
127
-
128
- def actually_destroyed?
129
- @_actually_destroyed
130
- end
131
-
132
- def clear_destroy_state
133
- @_actually_destroyed = nil
134
- end
135
-
136
125
  private
137
126
 
138
127
  def _create_record(*)