activerecord 4.1.8 → 4.2.11.3

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 (186) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1165 -1591
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +15 -8
  5. data/lib/active_record/association_relation.rb +13 -0
  6. data/lib/active_record/associations/alias_tracker.rb +3 -12
  7. data/lib/active_record/associations/association.rb +16 -4
  8. data/lib/active_record/associations/association_scope.rb +84 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -14
  14. data/lib/active_record/associations/builder/has_many.rb +1 -1
  15. data/lib/active_record/associations/builder/has_one.rb +2 -2
  16. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  17. data/lib/active_record/associations/collection_association.rb +87 -30
  18. data/lib/active_record/associations/collection_proxy.rb +33 -35
  19. data/lib/active_record/associations/foreign_association.rb +11 -0
  20. data/lib/active_record/associations/has_many_association.rb +83 -22
  21. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  22. data/lib/active_record/associations/has_one_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  24. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -12
  26. data/lib/active_record/associations/preloader/association.rb +14 -10
  27. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  28. data/lib/active_record/associations/preloader.rb +37 -26
  29. data/lib/active_record/associations/singular_association.rb +17 -2
  30. data/lib/active_record/associations/through_association.rb +16 -12
  31. data/lib/active_record/associations.rb +158 -49
  32. data/lib/active_record/attribute.rb +163 -0
  33. data/lib/active_record/attribute_assignment.rb +20 -12
  34. data/lib/active_record/attribute_decorators.rb +66 -0
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  37. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  38. data/lib/active_record/attribute_methods/query.rb +1 -1
  39. data/lib/active_record/attribute_methods/read.rb +22 -59
  40. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -28
  42. data/lib/active_record/attribute_methods/write.rb +9 -24
  43. data/lib/active_record/attribute_methods.rb +57 -95
  44. data/lib/active_record/attribute_set/builder.rb +106 -0
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attributes.rb +147 -0
  47. data/lib/active_record/autosave_association.rb +30 -12
  48. data/lib/active_record/base.rb +13 -24
  49. data/lib/active_record/callbacks.rb +6 -6
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +85 -53
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +139 -57
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
  62. data/lib/active_record/connection_adapters/column.rb +29 -240
  63. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +17 -33
  65. data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
  66. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  67. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  69. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -385
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  97. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +134 -43
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  101. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  103. data/lib/active_record/connection_handling.rb +1 -1
  104. data/lib/active_record/core.rb +163 -40
  105. data/lib/active_record/counter_cache.rb +60 -6
  106. data/lib/active_record/enum.rb +10 -12
  107. data/lib/active_record/errors.rb +53 -30
  108. data/lib/active_record/explain.rb +1 -1
  109. data/lib/active_record/explain_subscriber.rb +1 -1
  110. data/lib/active_record/fixtures.rb +62 -74
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +35 -10
  113. data/lib/active_record/integration.rb +4 -4
  114. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  115. data/lib/active_record/locking/optimistic.rb +46 -26
  116. data/lib/active_record/migration/command_recorder.rb +19 -2
  117. data/lib/active_record/migration/join_table.rb +1 -1
  118. data/lib/active_record/migration.rb +79 -47
  119. data/lib/active_record/model_schema.rb +52 -58
  120. data/lib/active_record/nested_attributes.rb +18 -8
  121. data/lib/active_record/no_touching.rb +1 -1
  122. data/lib/active_record/persistence.rb +48 -27
  123. data/lib/active_record/query_cache.rb +3 -3
  124. data/lib/active_record/querying.rb +10 -7
  125. data/lib/active_record/railtie.rb +19 -14
  126. data/lib/active_record/railties/databases.rake +55 -56
  127. data/lib/active_record/readonly_attributes.rb +0 -1
  128. data/lib/active_record/reflection.rb +281 -117
  129. data/lib/active_record/relation/batches.rb +0 -1
  130. data/lib/active_record/relation/calculations.rb +41 -37
  131. data/lib/active_record/relation/delegation.rb +1 -1
  132. data/lib/active_record/relation/finder_methods.rb +71 -48
  133. data/lib/active_record/relation/merger.rb +39 -29
  134. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  135. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  136. data/lib/active_record/relation/predicate_builder.rb +42 -12
  137. data/lib/active_record/relation/query_methods.rb +130 -73
  138. data/lib/active_record/relation/spawn_methods.rb +10 -3
  139. data/lib/active_record/relation.rb +57 -25
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -8
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +54 -28
  155. data/lib/active_record/type/big_integer.rb +13 -0
  156. data/lib/active_record/type/binary.rb +50 -0
  157. data/lib/active_record/type/boolean.rb +31 -0
  158. data/lib/active_record/type/date.rb +50 -0
  159. data/lib/active_record/type/date_time.rb +54 -0
  160. data/lib/active_record/type/decimal.rb +64 -0
  161. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  162. data/lib/active_record/type/decorator.rb +14 -0
  163. data/lib/active_record/type/float.rb +19 -0
  164. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  165. data/lib/active_record/type/integer.rb +59 -0
  166. data/lib/active_record/type/mutable.rb +16 -0
  167. data/lib/active_record/type/numeric.rb +36 -0
  168. data/lib/active_record/type/serialized.rb +62 -0
  169. data/lib/active_record/type/string.rb +40 -0
  170. data/lib/active_record/type/text.rb +11 -0
  171. data/lib/active_record/type/time.rb +26 -0
  172. data/lib/active_record/type/time_value.rb +38 -0
  173. data/lib/active_record/type/type_map.rb +64 -0
  174. data/lib/active_record/type/unsigned_integer.rb +15 -0
  175. data/lib/active_record/type/value.rb +110 -0
  176. data/lib/active_record/type.rb +23 -0
  177. data/lib/active_record/validations/associated.rb +5 -3
  178. data/lib/active_record/validations/presence.rb +5 -3
  179. data/lib/active_record/validations/uniqueness.rb +24 -20
  180. data/lib/active_record/validations.rb +25 -19
  181. data/lib/active_record.rb +5 -0
  182. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  183. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  184. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  185. metadata +66 -11
  186. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -46,6 +46,12 @@ module ActiveRecord
46
46
  end
47
47
  end
48
48
 
49
+ class HasOneAssociationPolymorphicThroughError < ActiveRecordError #:nodoc:
50
+ def initialize(owner_class_name, reflection)
51
+ super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
52
+ end
53
+ end
54
+
49
55
  class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
50
56
  def initialize(reflection)
51
57
  through_reflection = reflection.through_reflection
@@ -110,6 +116,7 @@ module ActiveRecord
110
116
  autoload :Association, 'active_record/associations/association'
111
117
  autoload :SingularAssociation, 'active_record/associations/singular_association'
112
118
  autoload :CollectionAssociation, 'active_record/associations/collection_association'
119
+ autoload :ForeignAssociation, 'active_record/associations/foreign_association'
113
120
  autoload :CollectionProxy, 'active_record/associations/collection_proxy'
114
121
 
115
122
  autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
@@ -202,12 +209,13 @@ module ActiveRecord
202
209
  # For instance, +attributes+ and +connection+ would be bad choices for association names.
203
210
  #
204
211
  # == Auto-generated methods
212
+ # See also Instance Public methods below for more details.
205
213
  #
206
214
  # === Singular associations (one-to-one)
207
215
  # | | belongs_to |
208
216
  # generated methods | belongs_to | :polymorphic | has_one
209
217
  # ----------------------------------+------------+--------------+---------
210
- # other | X | X | X
218
+ # other(force_reload=false) | X | X | X
211
219
  # other=(other) | X | X | X
212
220
  # build_other(attributes={}) | X | | X
213
221
  # create_other(attributes={}) | X | | X
@@ -217,7 +225,7 @@ module ActiveRecord
217
225
  # | | | has_many
218
226
  # generated methods | habtm | has_many | :through
219
227
  # ----------------------------------+-------+----------+----------
220
- # others | X | X | X
228
+ # others(force_reload=false) | X | X | X
221
229
  # others=(other,other,...) | X | X | X
222
230
  # other_ids | X | X | X
223
231
  # other_ids=(id,id,...) | X | X | X
@@ -419,6 +427,10 @@ module ActiveRecord
419
427
  # has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
420
428
  # end
421
429
  #
430
+ # Note: Joining, eager loading and preloading of these associations is not fully possible.
431
+ # These operations happen before instance creation and the scope will be called with a +nil+ argument.
432
+ # This can lead to unexpected behavior and is deprecated.
433
+ #
422
434
  # == Association callbacks
423
435
  #
424
436
  # Similar to the normal callbacks that hook into the life cycle of an Active Record object,
@@ -442,9 +454,11 @@ module ActiveRecord
442
454
  #
443
455
  # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
444
456
  #
445
- # Should any of the +before_add+ callbacks throw an exception, the object does not get
446
- # added to the collection. Same with the +before_remove+ callbacks; if an exception is
447
- # thrown the object doesn't get removed.
457
+ # If any of the +before_add+ callbacks throw an exception, the object will not be
458
+ # added to the collection.
459
+ #
460
+ # Similarly, if any of the +before_remove+ callbacks throw an exception, the object
461
+ # will not be removed from the collection.
448
462
  #
449
463
  # == Association extensions
450
464
  #
@@ -536,8 +550,8 @@ module ActiveRecord
536
550
  # end
537
551
  #
538
552
  # @firm = Firm.first
539
- # @firm.clients.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm
540
- # @firm.invoices # selects all invoices by going through the Client join model
553
+ # @firm.clients.flat_map { |c| c.invoices } # select all invoices for all clients of the firm
554
+ # @firm.invoices # selects all invoices by going through the Client join model
541
555
  #
542
556
  # Similarly you can go through a +has_one+ association on the join model:
543
557
  #
@@ -642,7 +656,7 @@ module ActiveRecord
642
656
  # belongs_to :commenter
643
657
  # end
644
658
  #
645
- # When using nested association, you will not be able to modify the association because there
659
+ # When using a nested association, you will not be able to modify the association because there
646
660
  # is not enough information to know what modification to make. For example, if you tried to
647
661
  # add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
648
662
  # intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
@@ -712,9 +726,9 @@ module ActiveRecord
712
726
  # == Eager loading of associations
713
727
  #
714
728
  # Eager loading is a way to find objects of a certain class and a number of named associations.
715
- # This is one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100
729
+ # It is one of the easiest ways to prevent the dreaded N+1 problem in which fetching 100
716
730
  # posts that each need to display their author triggers 101 database queries. Through the
717
- # use of eager loading, the 101 queries can be reduced to 2.
731
+ # use of eager loading, the number of queries will be reduced from 101 to 2.
718
732
  #
719
733
  # class Post < ActiveRecord::Base
720
734
  # belongs_to :author
@@ -744,16 +758,16 @@ module ActiveRecord
744
758
  # Post.includes(:author, :comments).each do |post|
745
759
  #
746
760
  # This will load all comments with a single query. This reduces the total number of queries
747
- # to 3. More generally the number of queries will be 1 plus the number of associations
761
+ # to 3. In general, the number of queries will be 1 plus the number of associations
748
762
  # named (except if some of the associations are polymorphic +belongs_to+ - see below).
749
763
  #
750
764
  # To include a deep hierarchy of associations, use a hash:
751
765
  #
752
- # Post.includes(:author, {comments: {author: :gravatar}}).each do |post|
766
+ # Post.includes(:author, { comments: { author: :gravatar } }).each do |post|
753
767
  #
754
- # That'll grab not only all the comments but all their authors and gravatar pictures.
755
- # You can mix and match symbols, arrays and hashes in any combination to describe the
756
- # associations you want to load.
768
+ # The above code will load all the comments and all of their associated
769
+ # authors and gravatars. You can mix and match any combination of symbols,
770
+ # arrays, and hashes to retrieve the associations you want to load.
757
771
  #
758
772
  # All of this power shouldn't fool you into thinking that you can pull out huge amounts
759
773
  # of data with no performance penalty just because you've reduced the number of queries.
@@ -762,8 +776,8 @@ module ActiveRecord
762
776
  # cut down on the number of queries in a situation as the one described above.
763
777
  #
764
778
  # Since only one table is loaded at a time, conditions or orders cannot reference tables
765
- # other than the main one. If this is the case Active Record falls back to the previously
766
- # used LEFT OUTER JOIN based strategy. For example
779
+ # other than the main one. If this is the case, Active Record falls back to the previously
780
+ # used LEFT OUTER JOIN based strategy. For example:
767
781
  #
768
782
  # Post.includes([:author, :comments]).where(['comments.approved = ?', true])
769
783
  #
@@ -774,16 +788,15 @@ module ActiveRecord
774
788
  # In the above example posts with no approved comments are not returned at all, because
775
789
  # the conditions apply to the SQL statement as a whole and not just to the association.
776
790
  #
791
+ # You must disambiguate column references for this fallback to happen, for example
792
+ # <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
793
+ #
777
794
  # If you want to load all posts (including posts with no approved comments) then write
778
795
  # your own LEFT OUTER JOIN query using ON
779
796
  #
780
- # Post.joins('LEFT OUTER JOIN comments ON comments.post_id = posts.id AND comments.approved = true')
781
- #
782
- # You must disambiguate column references for this fallback to happen, for example
783
- # <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
797
+ # Post.joins("LEFT OUTER JOIN comments ON comments.post_id = posts.id AND comments.approved = '1'")
784
798
  #
785
- # If you do want eager load only some members of an association it is usually more natural
786
- # to include an association which has conditions defined on it:
799
+ # In this case it is usually more natural to include an association which has conditions defined on it:
787
800
  #
788
801
  # class Post < ActiveRecord::Base
789
802
  # has_many :approved_comments, -> { where approved: true }, class_name: 'Comment'
@@ -999,7 +1012,7 @@ module ActiveRecord
999
1012
  # record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either
1000
1013
  # do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
1001
1014
  # if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
1002
- # The default strategy is <tt>:nullify</tt> (set the foreign keys to <tt>nil</tt>), except for
1015
+ # The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for
1003
1016
  # +has_many+ <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete
1004
1017
  # the join records, without running their callbacks).
1005
1018
  #
@@ -1048,6 +1061,9 @@ module ActiveRecord
1048
1061
  # Specifies a one-to-many association. The following methods for retrieval and query of
1049
1062
  # collections of associated objects will be added:
1050
1063
  #
1064
+ # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
1065
+ # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
1066
+ #
1051
1067
  # [collection(force_reload = false)]
1052
1068
  # Returns an array of all the associated objects.
1053
1069
  # An empty array is returned if none are found.
@@ -1106,9 +1122,6 @@ module ActiveRecord
1106
1122
  # Does the same as <tt>collection.create</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
1107
1123
  # if the record is invalid.
1108
1124
  #
1109
- # (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
1110
- # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
1111
- #
1112
1125
  # === Example
1113
1126
  #
1114
1127
  # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
@@ -1127,7 +1140,32 @@ module ActiveRecord
1127
1140
  # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
1128
1141
  # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
1129
1142
  # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
1130
- # The declaration can also include an options hash to specialize the behavior of the association.
1143
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
1144
+ #
1145
+ # === Scopes
1146
+ #
1147
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
1148
+ # lambda) to retrieve a specific set of records or customize the generated
1149
+ # query when you access the associated collection.
1150
+ #
1151
+ # Scope examples:
1152
+ # has_many :comments, -> { where(author_id: 1) }
1153
+ # has_many :employees, -> { joins(:address) }
1154
+ # has_many :posts, ->(post) { where("max_post_length > ?", post.length) }
1155
+ #
1156
+ # === Extensions
1157
+ #
1158
+ # The +extension+ argument allows you to pass a block into a has_many
1159
+ # association. This is useful for adding new finders, creators and other
1160
+ # factory-type methods to be used as part of the association.
1161
+ #
1162
+ # Extension examples:
1163
+ # has_many :employees do
1164
+ # def find_or_create_by_name(name)
1165
+ # first_name, last_name = name.split(" ", 2)
1166
+ # find_or_create_by(first_name: first_name, last_name: last_name)
1167
+ # end
1168
+ # end
1131
1169
  #
1132
1170
  # === Options
1133
1171
  # [:class_name]
@@ -1139,8 +1177,14 @@ module ActiveRecord
1139
1177
  # Specify the foreign key used for the association. By default this is guessed to be the name
1140
1178
  # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+
1141
1179
  # association will use "person_id" as the default <tt>:foreign_key</tt>.
1180
+ # [:foreign_type]
1181
+ # Specify the column used to store the associated object's type, if this is a polymorphic
1182
+ # association. By default this is guessed to be the name of the polymorphic association
1183
+ # specified on "as" option with a "_type" suffix. So a class that defines a
1184
+ # <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the
1185
+ # default <tt>:foreign_type</tt>.
1142
1186
  # [:primary_key]
1143
- # Specify the method that returns the primary key used for the association. By default this is +id+.
1187
+ # Specify the name of the column to use as the primary key for the association. By default this is +id+.
1144
1188
  # [:dependent]
1145
1189
  # Controls what happens to the associated objects when
1146
1190
  # their owner is destroyed. Note that these are implemented as
@@ -1205,7 +1249,7 @@ module ActiveRecord
1205
1249
  # Option examples:
1206
1250
  # has_many :comments, -> { order "posted_on" }
1207
1251
  # has_many :comments, -> { includes :author }
1208
- # has_many :people, -> { where("deleted = 0").order("name") }, class_name: "Person"
1252
+ # has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person"
1209
1253
  # has_many :tracks, -> { order "position" }, dependent: :destroy
1210
1254
  # has_many :comments, dependent: :nullify
1211
1255
  # has_many :tags, as: :taggable
@@ -1223,6 +1267,9 @@ module ActiveRecord
1223
1267
  #
1224
1268
  # The following methods for retrieval and query of a single associated object will be added:
1225
1269
  #
1270
+ # +association+ is a placeholder for the symbol passed as the +name+ argument, so
1271
+ # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
1272
+ #
1226
1273
  # [association(force_reload = false)]
1227
1274
  # Returns the associated object. +nil+ is returned if none is found.
1228
1275
  # [association=(associate)]
@@ -1241,9 +1288,6 @@ module ActiveRecord
1241
1288
  # Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
1242
1289
  # if the record is invalid.
1243
1290
  #
1244
- # (+association+ is replaced with the symbol passed as the first argument, so
1245
- # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.)
1246
- #
1247
1291
  # === Example
1248
1292
  #
1249
1293
  # An Account class declares <tt>has_one :beneficiary</tt>, which will add:
@@ -1253,9 +1297,20 @@ module ActiveRecord
1253
1297
  # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
1254
1298
  # * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
1255
1299
  #
1300
+ # === Scopes
1301
+ #
1302
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
1303
+ # lambda) to retrieve a specific record or customize the generated query
1304
+ # when you access the associated object.
1305
+ #
1306
+ # Scope examples:
1307
+ # has_one :author, -> { where(comment_id: 1) }
1308
+ # has_one :employer, -> { joins(:company) }
1309
+ # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) }
1310
+ #
1256
1311
  # === Options
1257
1312
  #
1258
- # The declaration can also include an options hash to specialize the behavior of the association.
1313
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
1259
1314
  #
1260
1315
  # Options are:
1261
1316
  # [:class_name]
@@ -1275,6 +1330,12 @@ module ActiveRecord
1275
1330
  # Specify the foreign key used for the association. By default this is guessed to be the name
1276
1331
  # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association
1277
1332
  # will use "person_id" as the default <tt>:foreign_key</tt>.
1333
+ # [:foreign_type]
1334
+ # Specify the column used to store the associated object's type, if this is a polymorphic
1335
+ # association. By default this is guessed to be the name of the polymorphic association
1336
+ # specified on "as" option with a "_type" suffix. So a class that defines a
1337
+ # <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the
1338
+ # default <tt>:foreign_type</tt>.
1278
1339
  # [:primary_key]
1279
1340
  # Specify the method that returns the primary key used for the association. By default this is +id+.
1280
1341
  # [:as]
@@ -1305,6 +1366,10 @@ module ActiveRecord
1305
1366
  # that is the inverse of this <tt>has_one</tt> association. Does not work in combination
1306
1367
  # with <tt>:through</tt> or <tt>:as</tt> options.
1307
1368
  # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1369
+ # [:required]
1370
+ # When set to +true+, the association will also have its presence validated.
1371
+ # This will validate the association itself, not the id. You can use
1372
+ # +:inverse_of+ to avoid an extra query during validation.
1308
1373
  #
1309
1374
  # Option examples:
1310
1375
  # has_one :credit_card, dependent: :destroy # destroys the associated credit card
@@ -1313,9 +1378,10 @@ module ActiveRecord
1313
1378
  # has_one :last_comment, -> { order 'posted_on' }, class_name: "Comment"
1314
1379
  # has_one :project_manager, -> { where role: 'project_manager' }, class_name: "Person"
1315
1380
  # has_one :attachment, as: :attachable
1316
- # has_one :boss, readonly: :true
1381
+ # has_one :boss, -> { readonly }
1317
1382
  # has_one :club, through: :membership
1318
1383
  # has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
1384
+ # has_one :credit_card, required: true
1319
1385
  def has_one(name, scope = nil, options = {})
1320
1386
  reflection = Builder::HasOne.build(self, name, scope, options)
1321
1387
  Reflection.add_reflection self, name, reflection
@@ -1329,6 +1395,9 @@ module ActiveRecord
1329
1395
  # Methods will be added for retrieval and query for a single associated object, for which
1330
1396
  # this object holds an id:
1331
1397
  #
1398
+ # +association+ is a placeholder for the symbol passed as the +name+ argument, so
1399
+ # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
1400
+ #
1332
1401
  # [association(force_reload = false)]
1333
1402
  # Returns the associated object. +nil+ is returned if none is found.
1334
1403
  # [association=(associate)]
@@ -1344,9 +1413,6 @@ module ActiveRecord
1344
1413
  # Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
1345
1414
  # if the record is invalid.
1346
1415
  #
1347
- # (+association+ is replaced with the symbol passed as the first argument, so
1348
- # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.)
1349
- #
1350
1416
  # === Example
1351
1417
  #
1352
1418
  # A Post class declares <tt>belongs_to :author</tt>, which will add:
@@ -1355,7 +1421,18 @@ module ActiveRecord
1355
1421
  # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
1356
1422
  # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
1357
1423
  # * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
1358
- # The declaration can also include an options hash to specialize the behavior of the association.
1424
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
1425
+ #
1426
+ # === Scopes
1427
+ #
1428
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
1429
+ # lambda) to retrieve a specific record or customize the generated query
1430
+ # when you access the associated object.
1431
+ #
1432
+ # Scope examples:
1433
+ # belongs_to :user, -> { where(id: 2) }
1434
+ # belongs_to :user, -> { joins(:friends) }
1435
+ # belongs_to :level, ->(level) { where("game_level > ?", level.current) }
1359
1436
  #
1360
1437
  # === Options
1361
1438
  #
@@ -1409,7 +1486,7 @@ module ActiveRecord
1409
1486
  #
1410
1487
  # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
1411
1488
  # [:touch]
1412
- # If true, the associated object will be touched (the updated_at/on attributes set to now)
1489
+ # If true, the associated object will be touched (the updated_at/on attributes set to current time)
1413
1490
  # when this record is either saved or destroyed. If you specify a symbol, that attribute
1414
1491
  # will be updated with the current time in addition to the updated_at/on attribute.
1415
1492
  # [:inverse_of]
@@ -1417,6 +1494,10 @@ module ActiveRecord
1417
1494
  # object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
1418
1495
  # combination with the <tt>:polymorphic</tt> options.
1419
1496
  # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1497
+ # [:required]
1498
+ # When set to +true+, the association will also have its presence validated.
1499
+ # This will validate the association itself, not the id. You can use
1500
+ # +:inverse_of+ to avoid an extra query during validation.
1420
1501
  #
1421
1502
  # Option examples:
1422
1503
  # belongs_to :firm, foreign_key: "client_of"
@@ -1425,10 +1506,11 @@ module ActiveRecord
1425
1506
  # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count },
1426
1507
  # class_name: "Coupon", foreign_key: "coupon_id"
1427
1508
  # belongs_to :attachable, polymorphic: true
1428
- # belongs_to :project, readonly: true
1509
+ # belongs_to :project, -> { readonly }
1429
1510
  # belongs_to :post, counter_cache: true
1430
1511
  # belongs_to :company, touch: true
1431
1512
  # belongs_to :company, touch: :employees_last_updated_at
1513
+ # belongs_to :company, required: true
1432
1514
  def belongs_to(name, scope = nil, options = {})
1433
1515
  reflection = Builder::BelongsTo.build(self, name, scope, options)
1434
1516
  Reflection.add_reflection self, name, reflection
@@ -1466,6 +1548,9 @@ module ActiveRecord
1466
1548
  #
1467
1549
  # Adds the following methods for retrieval and query:
1468
1550
  #
1551
+ # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
1552
+ # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
1553
+ #
1469
1554
  # [collection(force_reload = false)]
1470
1555
  # Returns an array of all the associated objects.
1471
1556
  # An empty array is returned if none are found.
@@ -1507,9 +1592,6 @@ module ActiveRecord
1507
1592
  # with +attributes+, linked to this object through the join table, and that has already been
1508
1593
  # saved (if it passed the validation).
1509
1594
  #
1510
- # (+collection+ is replaced with the symbol passed as the first argument, so
1511
- # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.)
1512
- #
1513
1595
  # === Example
1514
1596
  #
1515
1597
  # A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
@@ -1527,7 +1609,34 @@ module ActiveRecord
1527
1609
  # * <tt>Developer#projects.exists?(...)</tt>
1528
1610
  # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
1529
1611
  # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
1530
- # The declaration may include an options hash to specialize the behavior of the association.
1612
+ # The declaration may include an +options+ hash to specialize the behavior of the association.
1613
+ #
1614
+ # === Scopes
1615
+ #
1616
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
1617
+ # lambda) to retrieve a specific set of records or customize the generated
1618
+ # query when you access the associated collection.
1619
+ #
1620
+ # Scope examples:
1621
+ # has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
1622
+ # has_and_belongs_to_many :categories, ->(category) {
1623
+ # where("default_category = ?", category.name)
1624
+ # }
1625
+ #
1626
+ # === Extensions
1627
+ #
1628
+ # The +extension+ argument allows you to pass a block into a
1629
+ # has_and_belongs_to_many association. This is useful for adding new
1630
+ # finders, creators and other factory-type methods to be used as part of
1631
+ # the association.
1632
+ #
1633
+ # Extension examples:
1634
+ # has_and_belongs_to_many :contractors do
1635
+ # def find_or_create_by_name(name)
1636
+ # first_name, last_name = name.split(" ", 2)
1637
+ # find_or_create_by(first_name: first_name, last_name: last_name)
1638
+ # end
1639
+ # end
1531
1640
  #
1532
1641
  # === Options
1533
1642
  #
@@ -1573,7 +1682,7 @@ module ActiveRecord
1573
1682
  scope = nil
1574
1683
  end
1575
1684
 
1576
- habtm_reflection = ActiveRecord::Reflection::AssociationReflection.new(:has_and_belongs_to_many, name, scope, options, self)
1685
+ habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
1577
1686
 
1578
1687
  builder = Builder::HasAndBelongsToMany.new name, self, options
1579
1688
 
@@ -1588,7 +1697,7 @@ module ActiveRecord
1588
1697
 
1589
1698
  Builder::HasMany.define_callbacks self, middle_reflection
1590
1699
  Reflection.add_reflection self, middle_reflection.name, middle_reflection
1591
- middle_reflection.parent_reflection = [name.to_sym, habtm_reflection]
1700
+ middle_reflection.parent_reflection = [name.to_s, habtm_reflection]
1592
1701
 
1593
1702
  include Module.new {
1594
1703
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
@@ -1604,12 +1713,12 @@ module ActiveRecord
1604
1713
  hm_options[:through] = middle_reflection.name
1605
1714
  hm_options[:source] = join_model.right_reflection.name
1606
1715
 
1607
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table].each do |k|
1716
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
1608
1717
  hm_options[k] = options[k] if options.key? k
1609
1718
  end
1610
1719
 
1611
1720
  has_many name, scope, hm_options, &extension
1612
- self._reflections[name.to_sym].parent_reflection = [name.to_sym, habtm_reflection]
1721
+ self._reflections[name.to_s].parent_reflection = [name.to_s, habtm_reflection]
1613
1722
  end
1614
1723
  end
1615
1724
  end
@@ -0,0 +1,163 @@
1
+ module ActiveRecord
2
+ class Attribute # :nodoc:
3
+ class << self
4
+ def from_database(name, value, type)
5
+ FromDatabase.new(name, value, type)
6
+ end
7
+
8
+ def from_user(name, value, type)
9
+ FromUser.new(name, value, type)
10
+ end
11
+
12
+ def with_cast_value(name, value, type)
13
+ WithCastValue.new(name, value, type)
14
+ end
15
+
16
+ def null(name)
17
+ Null.new(name)
18
+ end
19
+
20
+ def uninitialized(name, type)
21
+ Uninitialized.new(name, type)
22
+ end
23
+ end
24
+
25
+ attr_reader :name, :value_before_type_cast, :type
26
+
27
+ # This method should not be called directly.
28
+ # Use #from_database or #from_user
29
+ def initialize(name, value_before_type_cast, type)
30
+ @name = name
31
+ @value_before_type_cast = value_before_type_cast
32
+ @type = type
33
+ end
34
+
35
+ def value
36
+ # `defined?` is cheaper than `||=` when we get back falsy values
37
+ @value = original_value unless defined?(@value)
38
+ @value
39
+ end
40
+
41
+ def original_value
42
+ type_cast(value_before_type_cast)
43
+ end
44
+
45
+ def value_for_database
46
+ type.type_cast_for_database(value)
47
+ end
48
+
49
+ def changed_from?(old_value)
50
+ type.changed?(old_value, value, value_before_type_cast)
51
+ end
52
+
53
+ def changed_in_place_from?(old_value)
54
+ has_been_read? && type.changed_in_place?(old_value, value)
55
+ end
56
+
57
+ def with_value_from_user(value)
58
+ self.class.from_user(name, value, type)
59
+ end
60
+
61
+ def with_value_from_database(value)
62
+ self.class.from_database(name, value, type)
63
+ end
64
+
65
+ def with_cast_value(value)
66
+ self.class.with_cast_value(name, value, type)
67
+ end
68
+
69
+ def type_cast(*)
70
+ raise NotImplementedError
71
+ end
72
+
73
+ def initialized?
74
+ true
75
+ end
76
+
77
+ def came_from_user?
78
+ false
79
+ end
80
+
81
+ def ==(other)
82
+ self.class == other.class &&
83
+ name == other.name &&
84
+ value_before_type_cast == other.value_before_type_cast &&
85
+ type == other.type
86
+ end
87
+
88
+ protected
89
+
90
+ def initialize_dup(other)
91
+ if defined?(@value) && @value.duplicable?
92
+ @value = @value.dup
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def has_been_read?
99
+ defined?(@value)
100
+ end
101
+
102
+ class FromDatabase < Attribute # :nodoc:
103
+ def type_cast(value)
104
+ type.type_cast_from_database(value)
105
+ end
106
+ end
107
+
108
+ class FromUser < Attribute # :nodoc:
109
+ def type_cast(value)
110
+ type.type_cast_from_user(value)
111
+ end
112
+
113
+ def came_from_user?
114
+ true
115
+ end
116
+ end
117
+
118
+ class WithCastValue < Attribute # :nodoc:
119
+ def type_cast(value)
120
+ value
121
+ end
122
+
123
+ def changed_in_place_from?(old_value)
124
+ false
125
+ end
126
+ end
127
+
128
+ class Null < Attribute # :nodoc:
129
+ def initialize(name)
130
+ super(name, nil, Type::Value.new)
131
+ end
132
+
133
+ def value
134
+ nil
135
+ end
136
+
137
+ def with_value_from_database(value)
138
+ raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
139
+ end
140
+ alias_method :with_value_from_user, :with_value_from_database
141
+ end
142
+
143
+ class Uninitialized < Attribute # :nodoc:
144
+ def initialize(name, type)
145
+ super(name, nil, type)
146
+ end
147
+
148
+ def value
149
+ if block_given?
150
+ yield name
151
+ end
152
+ end
153
+
154
+ def value_for_database
155
+ end
156
+
157
+ def initialized?
158
+ false
159
+ end
160
+ end
161
+ private_constant :FromDatabase, :FromUser, :Null, :Uninitialized
162
+ end
163
+ end