activerecord 3.2.19 → 5.0.0

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 (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2011 David Heinemeier Hansson
1
+ Copyright (c) 2004-2016 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
17
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = Active Record -- Object-relational mapping put on rails
1
+ = Active Record -- Object-relational mapping in Rails
2
2
 
3
3
  Active Record connects classes to relational database tables to establish an
4
4
  almost zero-configuration persistence layer for applications. The library
@@ -20,19 +20,19 @@ A short rundown of some of the major features:
20
20
  class Product < ActiveRecord::Base
21
21
  end
22
22
 
23
- The Product class is automatically mapped to the table named "products",
24
- which might look like this:
23
+ {Learn more}[link:classes/ActiveRecord/Base.html]
24
+
25
+ The Product class is automatically mapped to the table named "products",
26
+ which might look like this:
25
27
 
26
28
  CREATE TABLE products (
27
- id int(11) NOT NULL auto_increment,
29
+ id int NOT NULL auto_increment,
28
30
  name varchar(255),
29
31
  PRIMARY KEY (id)
30
32
  );
31
33
 
32
- This would also define the following accessors: `Product#name` and
33
- `Product#name=(new_name)`
34
-
35
- {Learn more}[link:classes/ActiveRecord/Base.html]
34
+ This would also define the following accessors: <tt>Product#name</tt> and
35
+ <tt>Product#name=(new_name)</tt>.
36
36
 
37
37
 
38
38
  * Associations between objects defined by simple class methods.
@@ -49,10 +49,10 @@ A short rundown of some of the major features:
49
49
  * Aggregations of value objects.
50
50
 
51
51
  class Account < ActiveRecord::Base
52
- composed_of :balance, :class_name => "Money",
53
- :mapping => %w(balance amount)
52
+ composed_of :balance, class_name: 'Money',
53
+ mapping: %w(balance amount)
54
54
  composed_of :address,
55
- :mapping => [%w(address_street street), %w(address_city city)]
55
+ mapping: [%w(address_street street), %w(address_city city)]
56
56
  end
57
57
 
58
58
  {Learn more}[link:classes/ActiveRecord/Aggregations/ClassMethods.html]
@@ -61,10 +61,10 @@ A short rundown of some of the major features:
61
61
  * Validation rules that can differ for new or existing objects.
62
62
 
63
63
  class Account < ActiveRecord::Base
64
- validates_presence_of :subdomain, :name, :email_address, :password
65
- validates_uniqueness_of :subdomain
66
- validates_acceptance_of :terms_of_service, :on => :create
67
- validates_confirmation_of :password, :email_address, :on => :create
64
+ validates :subdomain, :name, :email_address, :password, presence: true
65
+ validates :subdomain, uniqueness: true
66
+ validates :terms_of_service, acceptance: true, on: :create
67
+ validates :password, :email_address, confirmation: true, on: :create
68
68
  end
69
69
 
70
70
  {Learn more}[link:classes/ActiveRecord/Validations.html]
@@ -80,17 +80,6 @@ A short rundown of some of the major features:
80
80
  {Learn more}[link:classes/ActiveRecord/Callbacks.html]
81
81
 
82
82
 
83
- * Observers that react to changes in a model.
84
-
85
- class CommentObserver < ActiveRecord::Observer
86
- def after_create(comment) # is called just after Comment#save
87
- CommentMailer.new_comment_email("david@loudthinking.com", comment).deliver
88
- end
89
- end
90
-
91
- {Learn more}[link:classes/ActiveRecord/Observer.html]
92
-
93
-
94
83
  * Inheritance hierarchies.
95
84
 
96
85
  class Company < ActiveRecord::Base; end
@@ -124,32 +113,32 @@ A short rundown of some of the major features:
124
113
  * Database abstraction through simple adapters.
125
114
 
126
115
  # connect to SQLite3
127
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => "dbfile.sqlite3")
116
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'dbfile.sqlite3')
128
117
 
129
118
  # connect to MySQL with authentication
130
119
  ActiveRecord::Base.establish_connection(
131
- :adapter => "mysql2",
132
- :host => "localhost",
133
- :username => "me",
134
- :password => "secret",
135
- :database => "activerecord"
120
+ adapter: 'mysql2',
121
+ host: 'localhost',
122
+ username: 'me',
123
+ password: 'secret',
124
+ database: 'activerecord'
136
125
  )
137
126
 
138
127
  {Learn more}[link:classes/ActiveRecord/Base.html] and read about the built-in support for
139
- MySQL[link:classes/ActiveRecord/ConnectionAdapters/MysqlAdapter.html],
128
+ MySQL[link:classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html],
140
129
  PostgreSQL[link:classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html], and
141
130
  SQLite3[link:classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
142
131
 
143
132
 
144
- * Logging support for Log4r[http://log4r.sourceforge.net] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc].
133
+ * Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc].
145
134
 
146
- ActiveRecord::Base.logger = Logger.new(STDOUT)
147
- ActiveRecord::Base.logger = Log4r::Logger.new("Application Log")
135
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
136
+ ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
148
137
 
149
138
 
150
139
  * Database agnostic schema management with Migrations.
151
140
 
152
- class AddSystemSettings < ActiveRecord::Migration
141
+ class AddSystemSettings < ActiveRecord::Migration[5.0]
153
142
  def up
154
143
  create_table :system_settings do |t|
155
144
  t.string :name
@@ -159,7 +148,7 @@ A short rundown of some of the major features:
159
148
  t.integer :position
160
149
  end
161
150
 
162
- SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
151
+ SystemSetting.create name: 'notice', label: 'Use notice?', value: 1
163
152
  end
164
153
 
165
154
  def down
@@ -186,7 +175,7 @@ by relying on a number of conventions that make it easy for Active Record to inf
186
175
  complex relations and structures from a minimal amount of explicit direction.
187
176
 
188
177
  Convention over Configuration:
189
- * No XML-files!
178
+ * No XML files!
190
179
  * Lots of reflection and run-time extension
191
180
  * Magic is not inherently a bad word
192
181
 
@@ -199,24 +188,30 @@ Admit the Database:
199
188
 
200
189
  The latest version of Active Record can be installed with RubyGems:
201
190
 
202
- % [sudo] gem install activerecord
191
+ $ gem install activerecord
203
192
 
204
- Source code can be downloaded as part of the Rails project on GitHub
193
+ Source code can be downloaded as part of the Rails project on GitHub:
205
194
 
206
- * https://github.com/rails/rails/tree/3-2-stable/activerecord
195
+ * https://github.com/rails/rails/tree/master/activerecord
207
196
 
208
197
 
209
198
  == License
210
199
 
211
- Active Record is released under the MIT license.
200
+ Active Record is released under the MIT license:
201
+
202
+ * http://www.opensource.org/licenses/MIT
212
203
 
213
204
 
214
205
  == Support
215
206
 
216
- API documentation is at
207
+ API documentation is at:
217
208
 
218
209
  * http://api.rubyonrails.org
219
210
 
220
- Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
211
+ Bug reports can be filed for the Ruby on Rails project here:
221
212
 
222
213
  * https://github.com/rails/rails/issues
214
+
215
+ Feature requests should be discussed on the rails-core mailing list here:
216
+
217
+ * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
@@ -1,16 +1,15 @@
1
- require File.expand_path('../../../load_paths', __FILE__)
2
1
  require "active_record"
3
2
  require 'benchmark/ips'
4
3
 
5
4
  TIME = (ENV['BENCHMARK_TIME'] || 20).to_i
6
5
  RECORDS = (ENV['BENCHMARK_RECORDS'] || TIME*1000).to_i
7
6
 
8
- conn = { :adapter => 'sqlite3', :database => ':memory:' }
7
+ conn = { adapter: 'sqlite3', database: ':memory:' }
9
8
 
10
9
  ActiveRecord::Base.establish_connection(conn)
11
10
 
12
11
  class User < ActiveRecord::Base
13
- connection.create_table :users, :force => true do |t|
12
+ connection.create_table :users, force: true do |t|
14
13
  t.string :name, :email
15
14
  t.timestamps
16
15
  end
@@ -19,7 +18,7 @@ class User < ActiveRecord::Base
19
18
  end
20
19
 
21
20
  class Exhibit < ActiveRecord::Base
22
- connection.create_table :exhibits, :force => true do |t|
21
+ connection.create_table :exhibits, force: true do |t|
23
22
  t.belongs_to :user
24
23
  t.string :name
25
24
  t.text :notes
@@ -39,10 +38,12 @@ class Exhibit < ActiveRecord::Base
39
38
  where("notes IS NOT NULL")
40
39
  end
41
40
 
42
- def self.look(exhibits) exhibits.each { |e| e.look } end
43
- def self.feel(exhibits) exhibits.each { |e| e.feel } end
41
+ def self.look(exhibits) exhibits.each(&:look) end
42
+ def self.feel(exhibits) exhibits.each(&:feel) end
44
43
  end
45
44
 
45
+ def progress_bar(int); print "." if (int%100).zero? ; end
46
+
46
47
  puts 'Generating data...'
47
48
 
48
49
  module ActiveRecord
@@ -75,30 +76,32 @@ notes = ActiveRecord::Faker::LOREM.join ' '
75
76
  today = Date.today
76
77
 
77
78
  puts "Inserting #{RECORDS} users and exhibits..."
78
- RECORDS.times do
79
+ RECORDS.times do |record|
79
80
  user = User.create(
80
- :created_at => today,
81
- :name => ActiveRecord::Faker.name,
82
- :email => ActiveRecord::Faker.email
81
+ created_at: today,
82
+ name: ActiveRecord::Faker.name,
83
+ email: ActiveRecord::Faker.email
83
84
  )
84
85
 
85
86
  Exhibit.create(
86
- :created_at => today,
87
- :name => ActiveRecord::Faker.name,
88
- :user => user,
89
- :notes => notes
87
+ created_at: today,
88
+ name: ActiveRecord::Faker.name,
89
+ user: user,
90
+ notes: notes
90
91
  )
92
+ progress_bar(record)
91
93
  end
94
+ puts "Done!\n"
92
95
 
93
96
  Benchmark.ips(TIME) do |x|
94
97
  ar_obj = Exhibit.find(1)
95
- attrs = { :name => 'sam' }
96
- attrs_first = { :name => 'sam' }
97
- attrs_second = { :name => 'tom' }
98
+ attrs = { name: 'sam' }
99
+ attrs_first = { name: 'sam' }
100
+ attrs_second = { name: 'tom' }
98
101
  exhibit = {
99
- :name => ActiveRecord::Faker.name,
100
- :notes => notes,
101
- :created_at => Date.today
102
+ name: ActiveRecord::Faker.name,
103
+ notes: notes,
104
+ created_at: Date.today
102
105
  }
103
106
 
104
107
  x.report("Model#id") do
@@ -117,10 +120,18 @@ Benchmark.ips(TIME) do |x|
117
120
  Exhibit.first.look
118
121
  end
119
122
 
123
+ x.report 'Model.take' do
124
+ Exhibit.take
125
+ end
126
+
120
127
  x.report("Model.all limit(100)") do
121
128
  Exhibit.look Exhibit.limit(100)
122
129
  end
123
130
 
131
+ x.report("Model.all take(100)") do
132
+ Exhibit.look Exhibit.take(100)
133
+ end
134
+
124
135
  x.report "Model.all limit(100) with relationship" do
125
136
  Exhibit.feel Exhibit.limit(100).includes(:user)
126
137
  end
@@ -143,7 +154,7 @@ Benchmark.ips(TIME) do |x|
143
154
  end
144
155
 
145
156
  x.report 'Resource#update' do
146
- Exhibit.first.update_attributes(:name => 'bob')
157
+ Exhibit.first.update(name: 'bob')
147
158
  end
148
159
 
149
160
  x.report 'Resource#destroy' do
@@ -167,6 +178,6 @@ Benchmark.ips(TIME) do |x|
167
178
  end
168
179
 
169
180
  x.report "AR.execute(query)" do
170
- ActiveRecord::Base.connection.execute("Select * from exhibits where id = #{(rand * 1000 + 1).to_i}")
181
+ ActiveRecord::Base.connection.execute("SELECT * FROM exhibits WHERE id = #{(rand * 1000 + 1).to_i}")
171
182
  end
172
183
  end
data/examples/simple.rb CHANGED
@@ -1,14 +1,13 @@
1
- $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
2
1
  require 'active_record'
3
2
 
4
3
  class Person < ActiveRecord::Base
5
- establish_connection :adapter => 'sqlite3', :database => 'foobar.db'
6
- connection.create_table table_name, :force => true do |t|
4
+ establish_connection adapter: 'sqlite3', database: 'foobar.db'
5
+ connection.create_table table_name, force: true do |t|
7
6
  t.string :name
8
7
  end
9
8
  end
10
9
 
11
- bob = Person.create!(:name => 'bob')
10
+ bob = Person.create!(name: 'bob')
12
11
  puts Person.all.inspect
13
12
  bob.destroy
14
13
  puts Person.all.inspect
@@ -1,23 +1,40 @@
1
1
  module ActiveRecord
2
- # = Active Record Aggregations
3
- module Aggregations # :nodoc:
2
+ # See ActiveRecord::Aggregations::ClassMethods for documentation
3
+ module Aggregations
4
4
  extend ActiveSupport::Concern
5
5
 
6
- def clear_aggregation_cache #:nodoc:
7
- @aggregation_cache.clear if persisted?
6
+ def initialize_dup(*) # :nodoc:
7
+ @aggregation_cache = {}
8
+ super
8
9
  end
9
10
 
10
- # Active Record implements aggregation through a macro-like class method called +composed_of+
11
- # for representing attributes as value objects. It expresses relationships like "Account [is]
11
+ def reload(*) # :nodoc:
12
+ clear_aggregation_cache
13
+ super
14
+ end
15
+
16
+ private
17
+
18
+ def clear_aggregation_cache # :nodoc:
19
+ @aggregation_cache.clear if persisted?
20
+ end
21
+
22
+ def init_internals # :nodoc:
23
+ @aggregation_cache = {}
24
+ super
25
+ end
26
+
27
+ # Active Record implements aggregation through a macro-like class method called #composed_of
28
+ # for representing attributes as value objects. It expresses relationships like "Account [is]
12
29
  # composed of Money [among other things]" or "Person [is] composed of [an] address". Each call
13
- # to the macro adds a description of how the value objects are created from the attributes of
14
- # the entity object (when the entity is initialized either as a new object or from finding an
15
- # existing object) and how it can be turned back into attributes (when the entity is saved to
30
+ # to the macro adds a description of how the value objects are created from the attributes of
31
+ # the entity object (when the entity is initialized either as a new object or from finding an
32
+ # existing object) and how it can be turned back into attributes (when the entity is saved to
16
33
  # the database).
17
34
  #
18
35
  # class Customer < ActiveRecord::Base
19
- # composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
20
- # composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
36
+ # composed_of :balance, class_name: "Money", mapping: %w(amount currency)
37
+ # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
21
38
  # end
22
39
  #
23
40
  # The customer class now has the following methods to manipulate the value objects:
@@ -71,7 +88,7 @@ module ActiveRecord
71
88
  # Now it's possible to access attributes from the database through the value objects instead. If
72
89
  # you choose to name the composition the same as the attribute's name, it will be the only way to
73
90
  # access that attribute. That's the case with our +balance+ attribute. You interact with the value
74
- # objects just like you would any other attribute, though:
91
+ # objects just like you would with any other attribute:
75
92
  #
76
93
  # customer.balance = Money.new(20) # sets the Money value object and the attribute
77
94
  # customer.balance # => Money value object
@@ -86,6 +103,7 @@ module ActiveRecord
86
103
  # customer.address_street = "Hyancintvej"
87
104
  # customer.address_city = "Copenhagen"
88
105
  # customer.address # => Address.new("Hyancintvej", "Copenhagen")
106
+ #
89
107
  # customer.address = Address.new("May Street", "Chicago")
90
108
  # customer.address_street # => "May Street"
91
109
  # customer.address_city # => "Chicago"
@@ -101,13 +119,13 @@ module ActiveRecord
101
119
  # ActiveRecord::Base classes are entity objects.
102
120
  #
103
121
  # It's also important to treat the value objects as immutable. Don't allow the Money object to have
104
- # its amount changed after creation. Create a new Money object with the new value instead. This
105
- # is exemplified by the Money#exchange_to method that returns a new value object instead of changing
122
+ # its amount changed after creation. Create a new Money object with the new value instead. The
123
+ # <tt>Money#exchange_to</tt> method is an example of this. It returns a new value object instead of changing
106
124
  # its own values. Active Record won't persist value objects that have been changed through means
107
125
  # other than the writer method.
108
126
  #
109
127
  # The immutable requirement is enforced by Active Record by freezing any object assigned as a value
110
- # object. Attempting to change it afterwards will result in a ActiveSupport::FrozenObjectError.
128
+ # object. Attempting to change it afterwards will result in a +RuntimeError+.
111
129
  #
112
130
  # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not
113
131
  # keeping value objects immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
@@ -116,31 +134,31 @@ module ActiveRecord
116
134
  #
117
135
  # By default value objects are initialized by calling the <tt>new</tt> constructor of the value
118
136
  # class passing each of the mapped attributes, in the order specified by the <tt>:mapping</tt>
119
- # option, as arguments. If the value class doesn't support this convention then +composed_of+ allows
137
+ # option, as arguments. If the value class doesn't support this convention then #composed_of allows
120
138
  # a custom constructor to be specified.
121
139
  #
122
- # When a new value is assigned to the value object the default assumption is that the new value
140
+ # When a new value is assigned to the value object, the default assumption is that the new value
123
141
  # is an instance of the value class. Specifying a custom converter allows the new value to be automatically
124
142
  # converted to an instance of value class if necessary.
125
143
  #
126
- # For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that
127
- # should be aggregated using the NetAddr::CIDR value class (http://netaddr.rubyforge.org). The constructor
128
- # for the value class is called +create+ and it expects a CIDR address string as a parameter. New
129
- # values can be assigned to the value object using either another NetAddr::CIDR object, a string
144
+ # For example, the +NetworkResource+ model has +network_address+ and +cidr_range+ attributes that should be
145
+ # aggregated using the +NetAddr::CIDR+ value class (http://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR).
146
+ # The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter.
147
+ # New values can be assigned to the value object using either another +NetAddr::CIDR+ object, a string
130
148
  # or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
131
149
  # these requirements:
132
150
  #
133
151
  # class NetworkResource < ActiveRecord::Base
134
152
  # composed_of :cidr,
135
- # :class_name => 'NetAddr::CIDR',
136
- # :mapping => [ %w(network_address network), %w(cidr_range bits) ],
137
- # :allow_nil => true,
138
- # :constructor => Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
139
- # :converter => Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
153
+ # class_name: 'NetAddr::CIDR',
154
+ # mapping: [ %w(network_address network), %w(cidr_range bits) ],
155
+ # allow_nil: true,
156
+ # constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
157
+ # converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
140
158
  # end
141
159
  #
142
160
  # # This calls the :constructor
143
- # network_resource = NetworkResource.new(:network_address => '192.168.0.1', :cidr_range => 24)
161
+ # network_resource = NetworkResource.new(network_address: '192.168.0.1', cidr_range: 24)
144
162
  #
145
163
  # # These assignments will both use the :converter
146
164
  # network_resource.cidr = [ '192.168.2.1', 8 ]
@@ -155,11 +173,11 @@ module ActiveRecord
155
173
  #
156
174
  # == Finding records by a value object
157
175
  #
158
- # Once a +composed_of+ relationship is specified for a model, records can be loaded from the database
176
+ # Once a #composed_of relationship is specified for a model, records can be loaded from the database
159
177
  # by specifying an instance of the value object in the conditions hash. The following example
160
178
  # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD":
161
179
  #
162
- # Customer.where(:balance => Money.new(20, "USD")).all
180
+ # Customer.where(balance: Money.new(20, "USD"))
163
181
  #
164
182
  module ClassMethods
165
183
  # Adds reader and writer methods for manipulating a value object:
@@ -168,7 +186,7 @@ module ActiveRecord
168
186
  # Options are:
169
187
  # * <tt>:class_name</tt> - Specifies the class name of the association. Use it only if that name
170
188
  # can't be inferred from the part id. So <tt>composed_of :address</tt> will by default be linked
171
- # to the Address class, but if the real class name is CompanyAddress, you'll have to specify it
189
+ # to the Address class, but if the real class name is +CompanyAddress+, you'll have to specify it
172
190
  # with this option.
173
191
  # * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value
174
192
  # object. Each mapping is represented as an array where the first item is the name of the
@@ -187,20 +205,21 @@ module ActiveRecord
187
205
  # * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt>
188
206
  # or a Proc that is called when a new value is assigned to the value object. The converter is
189
207
  # passed the single value that is used in the assignment and is only called if the new value is
190
- # not an instance of <tt>:class_name</tt>.
208
+ # not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter
209
+ # can return nil to skip the assignment.
191
210
  #
192
211
  # Option examples:
193
- # composed_of :temperature, :mapping => %w(reading celsius)
194
- # composed_of :balance, :class_name => "Money", :mapping => %w(balance amount),
195
- # :converter => Proc.new { |balance| balance.to_money }
196
- # composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
212
+ # composed_of :temperature, mapping: %w(reading celsius)
213
+ # composed_of :balance, class_name: "Money", mapping: %w(balance amount),
214
+ # converter: Proc.new { |balance| balance.to_money }
215
+ # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
197
216
  # composed_of :gps_location
198
- # composed_of :gps_location, :allow_nil => true
217
+ # composed_of :gps_location, allow_nil: true
199
218
  # composed_of :ip_address,
200
- # :class_name => 'IPAddr',
201
- # :mapping => %w(ip to_i),
202
- # :constructor => Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
203
- # :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
219
+ # class_name: 'IPAddr',
220
+ # mapping: %w(ip to_i),
221
+ # constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
222
+ # converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
204
223
  #
205
224
  def composed_of(part_id, options = {})
206
225
  options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
@@ -216,14 +235,15 @@ module ActiveRecord
216
235
  reader_method(name, class_name, mapping, allow_nil, constructor)
217
236
  writer_method(name, class_name, mapping, allow_nil, converter)
218
237
 
219
- create_reflection(:composed_of, part_id, options, self)
238
+ reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self)
239
+ Reflection.add_aggregate_reflection self, part_id, reflection
220
240
  end
221
241
 
222
242
  private
223
243
  def reader_method(name, class_name, mapping, allow_nil, constructor)
224
244
  define_method(name) do
225
- if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|pair| !read_attribute(pair.first).nil? })
226
- attrs = mapping.collect {|pair| read_attribute(pair.first)}
245
+ if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !_read_attribute(key).nil? })
246
+ attrs = mapping.collect {|key, _| _read_attribute(key)}
227
247
  object = constructor.respond_to?(:call) ?
228
248
  constructor.call(*attrs) :
229
249
  class_name.constantize.send(constructor, *attrs)
@@ -235,17 +255,22 @@ module ActiveRecord
235
255
 
236
256
  def writer_method(name, class_name, mapping, allow_nil, converter)
237
257
  define_method("#{name}=") do |part|
258
+ klass = class_name.constantize
259
+
260
+ unless part.is_a?(klass) || converter.nil? || part.nil?
261
+ part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
262
+ end
263
+
264
+ if part.is_a?(Hash)
265
+ raise ArgumentError unless part.size == part.keys.max
266
+ part = klass.new(*part.sort.map(&:last))
267
+ end
268
+
238
269
  if part.nil? && allow_nil
239
- mapping.each { |pair| self[pair.first] = nil }
270
+ mapping.each { |key, _| self[key] = nil }
240
271
  @aggregation_cache[name] = nil
241
272
  else
242
- unless part.is_a?(class_name.constantize) || converter.nil?
243
- part = converter.respond_to?(:call) ?
244
- converter.call(part) :
245
- class_name.constantize.send(converter, part)
246
- end
247
-
248
- mapping.each { |pair| self[pair.first] = part.send(pair.last) }
273
+ mapping.each { |key, value| self[key] = part.send(value) }
249
274
  @aggregation_cache[name] = part.freeze
250
275
  end
251
276
  end
@@ -0,0 +1,35 @@
1
+ module ActiveRecord
2
+ class AssociationRelation < Relation
3
+ def initialize(klass, table, predicate_builder, association)
4
+ super(klass, table, predicate_builder)
5
+ @association = association
6
+ end
7
+
8
+ def proxy_association
9
+ @association
10
+ end
11
+
12
+ def ==(other)
13
+ other == records
14
+ end
15
+
16
+ def build(*args, &block)
17
+ scoping { @association.build(*args, &block) }
18
+ end
19
+ alias new build
20
+
21
+ def create(*args, &block)
22
+ scoping { @association.create(*args, &block) }
23
+ end
24
+
25
+ def create!(*args, &block)
26
+ scoping { @association.create!(*args, &block) }
27
+ end
28
+
29
+ private
30
+
31
+ def exec_queries
32
+ super.each { |r| @association.set_inverse_instance r }
33
+ end
34
+ end
35
+ end