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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1165 -1591
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +84 -43
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -14
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +87 -30
- data/lib/active_record/associations/collection_proxy.rb +33 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +26 -12
- data/lib/active_record/associations/preloader/association.rb +14 -10
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +37 -26
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +16 -12
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +20 -12
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -28
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_methods.rb +57 -95
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +30 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +85 -53
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +139 -57
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +17 -33
- data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -385
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +134 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -40
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +10 -12
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +62 -74
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +79 -47
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +18 -8
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +48 -27
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +19 -14
- data/lib/active_record/railties/databases.rake +55 -56
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +281 -117
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +71 -48
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +42 -12
- data/lib/active_record/relation/query_methods.rb +130 -73
- data/lib/active_record/relation/spawn_methods.rb +10 -3
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -8
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +54 -28
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +24 -20
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +66 -11
- 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
|
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
|
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
|
-
#
|
446
|
-
# added to the collection.
|
447
|
-
#
|
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.
|
540
|
-
# @firm.invoices
|
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
|
-
#
|
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
|
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.
|
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
|
-
#
|
755
|
-
# You can mix and match
|
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(
|
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
|
-
#
|
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
|
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
|
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(
|
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
|
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
|
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
|
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::
|
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.
|
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.
|
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
|