activerecord 3.1.10 → 4.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (237) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +1837 -338
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +39 -43
  5. data/examples/performance.rb +51 -20
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +57 -43
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -39
  10. data/lib/active_record/associations/association.rb +71 -85
  11. data/lib/active_record/associations/association_scope.rb +138 -89
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
  14. data/lib/active_record/associations/builder/association.rb +125 -29
  15. data/lib/active_record/associations/builder/belongs_to.rb +91 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +22 -29
  21. data/lib/active_record/associations/collection_association.rb +294 -187
  22. data/lib/active_record/associations/collection_proxy.rb +961 -94
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +118 -23
  25. data/lib/active_record/associations/has_many_through_association.rb +115 -45
  26. data/lib/active_record/associations/has_one_association.rb +57 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -102
  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 +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +61 -32
  38. data/lib/active_record/associations/preloader.rb +113 -87
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +37 -19
  41. data/lib/active_record/associations.rb +505 -371
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +212 -0
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +141 -51
  47. data/lib/active_record/attribute_methods/primary_key.rb +87 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +74 -117
  50. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
  52. data/lib/active_record/attribute_methods/write.rb +60 -21
  53. data/lib/active_record/attribute_methods.rb +409 -48
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +279 -232
  58. data/lib/active_record/base.rb +84 -1969
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +422 -243
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +273 -170
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
  75. data/lib/active_record/connection_adapters/column.rb +33 -221
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +445 -902
  114. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +159 -102
  119. data/lib/active_record/dynamic_matchers.rb +140 -0
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +102 -34
  122. data/lib/active_record/explain.rb +38 -0
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +29 -0
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +318 -260
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +247 -0
  129. data/lib/active_record/integration.rb +113 -0
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +80 -52
  133. data/lib/active_record/locking/pessimistic.rb +27 -5
  134. data/lib/active_record/log_subscriber.rb +25 -18
  135. data/lib/active_record/migration/command_recorder.rb +130 -38
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +532 -201
  138. data/lib/active_record/model_schema.rb +342 -0
  139. data/lib/active_record/nested_attributes.rb +229 -139
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +304 -99
  143. data/lib/active_record/query_cache.rb +25 -43
  144. data/lib/active_record/querying.rb +68 -0
  145. data/lib/active_record/railtie.rb +86 -45
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +7 -4
  148. data/lib/active_record/railties/databases.rake +198 -377
  149. data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
  150. data/lib/active_record/readonly_attributes.rb +23 -0
  151. data/lib/active_record/reflection.rb +516 -165
  152. data/lib/active_record/relation/batches.rb +96 -45
  153. data/lib/active_record/relation/calculations.rb +221 -144
  154. data/lib/active_record/relation/delegation.rb +140 -0
  155. data/lib/active_record/relation/finder_methods.rb +362 -243
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -41
  160. data/lib/active_record/relation/query_methods.rb +982 -155
  161. data/lib/active_record/relation/spawn_methods.rb +50 -110
  162. data/lib/active_record/relation.rb +371 -180
  163. data/lib/active_record/result.rb +109 -12
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +191 -0
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +111 -61
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +135 -0
  170. data/lib/active_record/scoping/named.rb +164 -0
  171. data/lib/active_record/scoping.rb +87 -0
  172. data/lib/active_record/serialization.rb +7 -45
  173. data/lib/active_record/serializers/xml_serializer.rb +14 -65
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +205 -0
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +35 -14
  181. data/lib/active_record/transactions.rb +141 -74
  182. data/lib/active_record/translation.rb +22 -0
  183. data/lib/active_record/type/big_integer.rb +13 -0
  184. data/lib/active_record/type/binary.rb +50 -0
  185. data/lib/active_record/type/boolean.rb +31 -0
  186. data/lib/active_record/type/date.rb +50 -0
  187. data/lib/active_record/type/date_time.rb +54 -0
  188. data/lib/active_record/type/decimal.rb +64 -0
  189. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  190. data/lib/active_record/type/decorator.rb +14 -0
  191. data/lib/active_record/type/float.rb +19 -0
  192. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  193. data/lib/active_record/type/integer.rb +59 -0
  194. data/lib/active_record/type/mutable.rb +16 -0
  195. data/lib/active_record/type/numeric.rb +36 -0
  196. data/lib/active_record/type/serialized.rb +62 -0
  197. data/lib/active_record/type/string.rb +40 -0
  198. data/lib/active_record/type/text.rb +11 -0
  199. data/lib/active_record/type/time.rb +26 -0
  200. data/lib/active_record/type/time_value.rb +38 -0
  201. data/lib/active_record/type/type_map.rb +64 -0
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type/value.rb +110 -0
  204. data/lib/active_record/type.rb +23 -0
  205. data/lib/active_record/validations/associated.rb +27 -18
  206. data/lib/active_record/validations/presence.rb +67 -0
  207. data/lib/active_record/validations/uniqueness.rb +125 -66
  208. data/lib/active_record/validations.rb +37 -30
  209. data/lib/active_record/version.rb +5 -7
  210. data/lib/active_record.rb +80 -25
  211. data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
  212. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  213. data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
  214. data/lib/rails/generators/active_record/migration.rb +11 -8
  215. data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
  216. data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
  217. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  218. data/lib/rails/generators/active_record.rb +3 -11
  219. metadata +132 -53
  220. data/examples/associations.png +0 -0
  221. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
  222. data/lib/active_record/associations/join_helper.rb +0 -55
  223. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
  226. data/lib/active_record/dynamic_finder_match.rb +0 -56
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/identity_map.rb +0 -163
  229. data/lib/active_record/named_scope.rb +0 -200
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -358
  232. data/lib/active_record/test_case.rb +0 -69
  233. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
  234. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  235. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  236. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  237. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2011 David Heinemeier Hansson
1
+ Copyright (c) 2004-2014 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
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,8 +20,10 @@ 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
29
  id int(11) NOT NULL auto_increment,
@@ -29,10 +31,8 @@ A short rundown of some of the major features:
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: `Product#name` and
35
+ `Product#name=(new_name)`.
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,15 +113,15 @@ 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
@@ -141,10 +130,10 @@ A short rundown of some of the major features:
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.
@@ -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
 
@@ -197,26 +186,33 @@ Admit the Database:
197
186
 
198
187
  == Download and installation
199
188
 
200
- The latest version of Active Record can be installed with Rubygems:
189
+ The latest version of Active Record can be installed with RubyGems:
201
190
 
202
191
  % [sudo] 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/master/activerecord
195
+ * https://github.com/rails/rails/tree/4-2-stable/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
- * http://api.rubyonrails.com
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
218
+
@@ -5,12 +5,12 @@ require 'benchmark/ips'
5
5
  TIME = (ENV['BENCHMARK_TIME'] || 20).to_i
6
6
  RECORDS = (ENV['BENCHMARK_RECORDS'] || TIME*1000).to_i
7
7
 
8
- conn = { :adapter => 'sqlite3', :database => ':memory:' }
8
+ conn = { adapter: 'sqlite3', database: ':memory:' }
9
9
 
10
10
  ActiveRecord::Base.establish_connection(conn)
11
11
 
12
12
  class User < ActiveRecord::Base
13
- connection.create_table :users, :force => true do |t|
13
+ connection.create_table :users, force: true do |t|
14
14
  t.string :name, :email
15
15
  t.timestamps
16
16
  end
@@ -19,7 +19,7 @@ class User < ActiveRecord::Base
19
19
  end
20
20
 
21
21
  class Exhibit < ActiveRecord::Base
22
- connection.create_table :exhibits, :force => true do |t|
22
+ connection.create_table :exhibits, force: true do |t|
23
23
  t.belongs_to :user
24
24
  t.string :name
25
25
  t.text :notes
@@ -31,15 +31,32 @@ class Exhibit < ActiveRecord::Base
31
31
  def look; attributes end
32
32
  def feel; look; user.name end
33
33
 
34
+ def self.with_name
35
+ where("name IS NOT NULL")
36
+ end
37
+
38
+ def self.with_notes
39
+ where("notes IS NOT NULL")
40
+ end
41
+
34
42
  def self.look(exhibits) exhibits.each { |e| e.look } end
35
43
  def self.feel(exhibits) exhibits.each { |e| e.feel } end
36
44
  end
37
45
 
46
+ def progress_bar(int); print "." if (int%100).zero? ; end
47
+
38
48
  puts 'Generating data...'
39
49
 
40
50
  module ActiveRecord
41
51
  class Faker
42
- LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse non aliquet diam. Curabitur vel urna metus, quis malesuada elit. Integer consequat tincidunt felis. Etiam non erat dolor. Vivamus imperdiet nibh sit amet diam eleifend id posuere diam malesuada. Mauris at accumsan sem. Donec id lorem neque. Fusce erat lorem, ornare eu congue vitae, malesuada quis neque. Maecenas vel urna a velit pretium fermentum. Donec tortor enim, tempor venenatis egestas a, tempor sed ipsum. Ut arcu justo, faucibus non imperdiet ac, interdum at diam. Pellentesque ipsum enim, venenatis ut iaculis vitae, varius vitae sem. Sed rutrum quam ac elit euismod bibendum. Donec ultricies ultricies magna, at lacinia libero mollis aliquam. Sed ac arcu in tortor elementum tincidunt vel interdum sem. Curabitur eget erat arcu. Praesent eget eros leo. Nam magna enim, sollicitudin vehicula scelerisque in, vulputate ut libero. Praesent varius tincidunt commodo".split
52
+ LOREM = %Q{Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse non aliquet diam. Curabitur vel urna metus, quis malesuada elit.
53
+ Integer consequat tincidunt felis. Etiam non erat dolor. Vivamus imperdiet nibh sit amet diam eleifend id posuere diam malesuada. Mauris at accumsan sem.
54
+ Donec id lorem neque. Fusce erat lorem, ornare eu congue vitae, malesuada quis neque. Maecenas vel urna a velit pretium fermentum. Donec tortor enim,
55
+ tempor venenatis egestas a, tempor sed ipsum. Ut arcu justo, faucibus non imperdiet ac, interdum at diam. Pellentesque ipsum enim, venenatis ut iaculis vitae,
56
+ varius vitae sem. Sed rutrum quam ac elit euismod bibendum. Donec ultricies ultricies magna, at lacinia libero mollis aliquam. Sed ac arcu in tortor elementum
57
+ tincidunt vel interdum sem. Curabitur eget erat arcu. Praesent eget eros leo. Nam magna enim, sollicitudin vehicula scelerisque in, vulputate ut libero.
58
+ Praesent varius tincidunt commodo}.split
59
+
43
60
  def self.name
44
61
  LOREM.grep(/^\w*$/).sort_by { rand }.first(2).join ' '
45
62
  end
@@ -60,30 +77,32 @@ notes = ActiveRecord::Faker::LOREM.join ' '
60
77
  today = Date.today
61
78
 
62
79
  puts "Inserting #{RECORDS} users and exhibits..."
63
- RECORDS.times do
80
+ RECORDS.times do |record|
64
81
  user = User.create(
65
- :created_at => today,
66
- :name => ActiveRecord::Faker.name,
67
- :email => ActiveRecord::Faker.email
82
+ created_at: today,
83
+ name: ActiveRecord::Faker.name,
84
+ email: ActiveRecord::Faker.email
68
85
  )
69
86
 
70
87
  Exhibit.create(
71
- :created_at => today,
72
- :name => ActiveRecord::Faker.name,
73
- :user => user,
74
- :notes => notes
88
+ created_at: today,
89
+ name: ActiveRecord::Faker.name,
90
+ user: user,
91
+ notes: notes
75
92
  )
93
+ progress_bar(record)
76
94
  end
95
+ puts "Done!\n"
77
96
 
78
97
  Benchmark.ips(TIME) do |x|
79
98
  ar_obj = Exhibit.find(1)
80
- attrs = { :name => 'sam' }
81
- attrs_first = { :name => 'sam' }
82
- attrs_second = { :name => 'tom' }
99
+ attrs = { name: 'sam' }
100
+ attrs_first = { name: 'sam' }
101
+ attrs_second = { name: 'tom' }
83
102
  exhibit = {
84
- :name => ActiveRecord::Faker.name,
85
- :notes => notes,
86
- :created_at => Date.today
103
+ name: ActiveRecord::Faker.name,
104
+ notes: notes,
105
+ created_at: Date.today
87
106
  }
88
107
 
89
108
  x.report("Model#id") do
@@ -102,10 +121,18 @@ Benchmark.ips(TIME) do |x|
102
121
  Exhibit.first.look
103
122
  end
104
123
 
124
+ x.report 'Model.take' do
125
+ Exhibit.take
126
+ end
127
+
105
128
  x.report("Model.all limit(100)") do
106
129
  Exhibit.look Exhibit.limit(100)
107
130
  end
108
131
 
132
+ x.report("Model.all take(100)") do
133
+ Exhibit.look Exhibit.take(100)
134
+ end
135
+
109
136
  x.report "Model.all limit(100) with relationship" do
110
137
  Exhibit.feel Exhibit.limit(100).includes(:user)
111
138
  end
@@ -114,6 +141,10 @@ Benchmark.ips(TIME) do |x|
114
141
  Exhibit.look Exhibit.limit(10000)
115
142
  end
116
143
 
144
+ x.report 'Model.named_scope' do
145
+ Exhibit.limit(10).with_name.with_notes
146
+ end
147
+
117
148
  x.report 'Model.create' do
118
149
  Exhibit.create(exhibit)
119
150
  end
@@ -124,7 +155,7 @@ Benchmark.ips(TIME) do |x|
124
155
  end
125
156
 
126
157
  x.report 'Resource#update' do
127
- Exhibit.first.update_attributes(:name => 'bob')
158
+ Exhibit.first.update(name: 'bob')
128
159
  end
129
160
 
130
161
  x.report 'Resource#destroy' do
@@ -148,6 +179,6 @@ Benchmark.ips(TIME) do |x|
148
179
  end
149
180
 
150
181
  x.report "AR.execute(query)" do
151
- ActiveRecord::Base.connection.execute("Select * from exhibits where id = #{(rand * 1000 + 1).to_i}")
182
+ ActiveRecord::Base.connection.execute("SELECT * FROM exhibits WHERE id = #{(rand * 1000 + 1).to_i}")
152
183
  end
153
184
  end
data/examples/simple.rb CHANGED
@@ -1,14 +1,14 @@
1
- $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
1
+ require File.expand_path('../../../load_paths', __FILE__)
2
2
  require 'active_record'
3
3
 
4
4
  class Person < ActiveRecord::Base
5
- establish_connection :adapter => 'sqlite3', :database => 'foobar.db'
6
- connection.create_table table_name, :force => true do |t|
5
+ establish_connection adapter: 'sqlite3', database: 'foobar.db'
6
+ connection.create_table table_name, force: true do |t|
7
7
  t.string :name
8
8
  end
9
9
  end
10
10
 
11
- bob = Person.create!(:name => 'bob')
11
+ bob = Person.create!(name: 'bob')
12
12
  puts Person.all.inspect
13
13
  bob.destroy
14
14
  puts Person.all.inspect
@@ -10,14 +10,14 @@ module ActiveRecord
10
10
  # Active Record implements aggregation through a macro-like class method called +composed_of+
11
11
  # for representing attributes as value objects. It expresses relationships like "Account [is]
12
12
  # 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
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
16
16
  # the database).
17
17
  #
18
18
  # 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) ]
19
+ # composed_of :balance, class_name: "Money", mapping: %w(balance amount)
20
+ # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
21
21
  # end
22
22
  #
23
23
  # The customer class now has the following methods to manipulate the value objects:
@@ -71,7 +71,7 @@ module ActiveRecord
71
71
  # Now it's possible to access attributes from the database through the value objects instead. If
72
72
  # you choose to name the composition the same as the attribute's name, it will be the only way to
73
73
  # 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:
74
+ # objects just like you would with any other attribute:
75
75
  #
76
76
  # customer.balance = Money.new(20) # sets the Money value object and the attribute
77
77
  # customer.balance # => Money value object
@@ -86,6 +86,12 @@ module ActiveRecord
86
86
  # customer.address_street = "Hyancintvej"
87
87
  # customer.address_city = "Copenhagen"
88
88
  # customer.address # => Address.new("Hyancintvej", "Copenhagen")
89
+ #
90
+ # customer.address_street = "Vesterbrogade"
91
+ # customer.address # => Address.new("Hyancintvej", "Copenhagen")
92
+ # customer.clear_aggregation_cache
93
+ # customer.address # => Address.new("Vesterbrogade", "Copenhagen")
94
+ #
89
95
  # customer.address = Address.new("May Street", "Chicago")
90
96
  # customer.address_street # => "May Street"
91
97
  # customer.address_city # => "Chicago"
@@ -101,13 +107,13 @@ module ActiveRecord
101
107
  # ActiveRecord::Base classes are entity objects.
102
108
  #
103
109
  # 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
110
+ # its amount changed after creation. Create a new Money object with the new value instead. The
111
+ # Money#exchange_to method is an example of this. It returns a new value object instead of changing
106
112
  # its own values. Active Record won't persist value objects that have been changed through means
107
113
  # other than the writer method.
108
114
  #
109
115
  # 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.
116
+ # object. Attempting to change it afterwards will result in a RuntimeError.
111
117
  #
112
118
  # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not
113
119
  # keeping value objects immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
@@ -119,28 +125,28 @@ module ActiveRecord
119
125
  # option, as arguments. If the value class doesn't support this convention then +composed_of+ allows
120
126
  # a custom constructor to be specified.
121
127
  #
122
- # When a new value is assigned to the value object the default assumption is that the new value
128
+ # When a new value is assigned to the value object, the default assumption is that the new value
123
129
  # is an instance of the value class. Specifying a custom converter allows the new value to be automatically
124
130
  # converted to an instance of value class if necessary.
125
131
  #
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
132
+ # For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that should be
133
+ # aggregated using the NetAddr::CIDR value class (http://www.ruby-doc.org/gems/docs/n/netaddr-1.5.0/NetAddr/CIDR.html).
134
+ # The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter.
135
+ # New values can be assigned to the value object using either another NetAddr::CIDR object, a string
130
136
  # or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
131
137
  # these requirements:
132
138
  #
133
139
  # class NetworkResource < ActiveRecord::Base
134
140
  # 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) }
141
+ # class_name: 'NetAddr::CIDR',
142
+ # mapping: [ %w(network_address network), %w(cidr_range bits) ],
143
+ # allow_nil: true,
144
+ # constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
145
+ # converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
140
146
  # end
141
147
  #
142
148
  # # This calls the :constructor
143
- # network_resource = NetworkResource.new(:network_address => '192.168.0.1', :cidr_range => 24)
149
+ # network_resource = NetworkResource.new(network_address: '192.168.0.1', cidr_range: 24)
144
150
  #
145
151
  # # These assignments will both use the :converter
146
152
  # network_resource.cidr = [ '192.168.2.1', 8 ]
@@ -159,7 +165,7 @@ module ActiveRecord
159
165
  # by specifying an instance of the value object in the conditions hash. The following example
160
166
  # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD":
161
167
  #
162
- # Customer.where(:balance => Money.new(20, "USD")).all
168
+ # Customer.where(balance: Money.new(20, "USD"))
163
169
  #
164
170
  module ClassMethods
165
171
  # Adds reader and writer methods for manipulating a value object:
@@ -176,7 +182,7 @@ module ActiveRecord
176
182
  # order in which mappings are defined determines the order in which attributes are sent to the
177
183
  # value class constructor.
178
184
  # * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped
179
- # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
185
+ # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
180
186
  # mapped attributes.
181
187
  # This defaults to +false+.
182
188
  # * <tt>:constructor</tt> - A symbol specifying the name of the constructor method or a Proc that
@@ -187,20 +193,21 @@ module ActiveRecord
187
193
  # * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt>
188
194
  # or a Proc that is called when a new value is assigned to the value object. The converter is
189
195
  # 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>.
196
+ # not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter
197
+ # can return nil to skip the assignment.
191
198
  #
192
199
  # 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) ]
200
+ # composed_of :temperature, mapping: %w(reading celsius)
201
+ # composed_of :balance, class_name: "Money", mapping: %w(balance amount),
202
+ # converter: Proc.new { |balance| balance.to_money }
203
+ # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
197
204
  # composed_of :gps_location
198
- # composed_of :gps_location, :allow_nil => true
205
+ # composed_of :gps_location, allow_nil: true
199
206
  # 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) }
207
+ # class_name: 'IPAddr',
208
+ # mapping: %w(ip to_i),
209
+ # constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
210
+ # converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
204
211
  #
205
212
  def composed_of(part_id, options = {})
206
213
  options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
@@ -216,14 +223,15 @@ module ActiveRecord
216
223
  reader_method(name, class_name, mapping, allow_nil, constructor)
217
224
  writer_method(name, class_name, mapping, allow_nil, converter)
218
225
 
219
- create_reflection(:composed_of, part_id, options, self)
226
+ reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self)
227
+ Reflection.add_aggregate_reflection self, part_id, reflection
220
228
  end
221
229
 
222
230
  private
223
231
  def reader_method(name, class_name, mapping, allow_nil, constructor)
224
232
  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)}
233
+ if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !_read_attribute(key).nil? })
234
+ attrs = mapping.collect {|key, _| _read_attribute(key)}
227
235
  object = constructor.respond_to?(:call) ?
228
236
  constructor.call(*attrs) :
229
237
  class_name.constantize.send(constructor, *attrs)
@@ -235,17 +243,23 @@ module ActiveRecord
235
243
 
236
244
  def writer_method(name, class_name, mapping, allow_nil, converter)
237
245
  define_method("#{name}=") do |part|
246
+ klass = class_name.constantize
247
+
248
+ unless part.is_a?(klass) || converter.nil? || part.nil?
249
+ part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
250
+ end
251
+
252
+ hash_from_multiparameter_assignment = part.is_a?(Hash) &&
253
+ part.each_key.all? { |k| k.is_a?(Integer) }
254
+ if hash_from_multiparameter_assignment
255
+ part = klass.new(*part.values)
256
+ end
257
+
238
258
  if part.nil? && allow_nil
239
- mapping.each { |pair| self[pair.first] = nil }
259
+ mapping.each { |key, _| self[key] = nil }
240
260
  @aggregation_cache[name] = nil
241
261
  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) }
262
+ mapping.each { |key, value| self[key] = part.send(value) }
249
263
  @aggregation_cache[name] = part.freeze
250
264
  end
251
265
  end
@@ -0,0 +1,35 @@
1
+ module ActiveRecord
2
+ class AssociationRelation < Relation
3
+ def initialize(klass, table, association)
4
+ super(klass, table)
5
+ @association = association
6
+ end
7
+
8
+ def proxy_association
9
+ @association
10
+ end
11
+
12
+ def ==(other)
13
+ other == to_a
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