activerecord 4.2.0 → 5.2.8.1
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 +640 -928
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -339
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -19
- data/lib/active_record/scoping/default.rb +102 -84
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +208 -123
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +30 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +77 -53
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/array"
|
4
|
+
require "active_support/core_ext/hash/except"
|
5
|
+
require "active_support/core_ext/kernel/singleton_class"
|
4
6
|
|
5
7
|
module ActiveRecord
|
6
8
|
# = Active Record \Named \Scopes
|
@@ -9,7 +11,7 @@ module ActiveRecord
|
|
9
11
|
extend ActiveSupport::Concern
|
10
12
|
|
11
13
|
module ClassMethods
|
12
|
-
# Returns an
|
14
|
+
# Returns an ActiveRecord::Relation scope object.
|
13
15
|
#
|
14
16
|
# posts = Post.all
|
15
17
|
# posts.size # Fires "select count(*) from posts" and returns the count
|
@@ -20,32 +22,50 @@ module ActiveRecord
|
|
20
22
|
# fruits = fruits.limit(10) if limited?
|
21
23
|
#
|
22
24
|
# You can define a scope that applies to all finders using
|
23
|
-
#
|
25
|
+
# {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
|
24
26
|
def all
|
27
|
+
current_scope = self.current_scope
|
28
|
+
|
25
29
|
if current_scope
|
26
|
-
current_scope.
|
30
|
+
if self == current_scope.klass
|
31
|
+
current_scope.clone
|
32
|
+
else
|
33
|
+
relation.merge!(current_scope)
|
34
|
+
end
|
27
35
|
else
|
28
36
|
default_scoped
|
29
37
|
end
|
30
38
|
end
|
31
39
|
|
32
|
-
def
|
33
|
-
|
40
|
+
def scope_for_association(scope = relation) # :nodoc:
|
41
|
+
current_scope = self.current_scope
|
42
|
+
|
43
|
+
if current_scope && current_scope.empty_scope?
|
44
|
+
scope
|
45
|
+
else
|
46
|
+
default_scoped(scope)
|
47
|
+
end
|
34
48
|
end
|
35
49
|
|
36
|
-
|
37
|
-
|
38
|
-
def scope_attributes # :nodoc:
|
39
|
-
all.scope_for_create
|
50
|
+
def default_scoped(scope = relation) # :nodoc:
|
51
|
+
build_default_scope(scope) || scope
|
40
52
|
end
|
41
53
|
|
42
|
-
|
43
|
-
|
44
|
-
|
54
|
+
def default_extensions # :nodoc:
|
55
|
+
if scope = current_scope || build_default_scope
|
56
|
+
scope.extensions
|
57
|
+
else
|
58
|
+
[]
|
59
|
+
end
|
45
60
|
end
|
46
61
|
|
47
|
-
# Adds a class method for retrieving and querying objects.
|
48
|
-
#
|
62
|
+
# Adds a class method for retrieving and querying objects.
|
63
|
+
# The method is intended to return an ActiveRecord::Relation
|
64
|
+
# object, which is composable with other scopes.
|
65
|
+
# If it returns +nil+ or +false+, an
|
66
|
+
# {all}[rdoc-ref:Scoping::Named::ClassMethods#all] scope is returned instead.
|
67
|
+
#
|
68
|
+
# A \scope represents a narrowing of a database query, such as
|
49
69
|
# <tt>where(color: :red).select('shirts.*').includes(:washing_instructions)</tt>.
|
50
70
|
#
|
51
71
|
# class Shirt < ActiveRecord::Base
|
@@ -53,12 +73,12 @@ module ActiveRecord
|
|
53
73
|
# scope :dry_clean_only, -> { joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true) }
|
54
74
|
# end
|
55
75
|
#
|
56
|
-
# The above calls to
|
76
|
+
# The above calls to #scope define class methods <tt>Shirt.red</tt> and
|
57
77
|
# <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, in effect,
|
58
78
|
# represents the query <tt>Shirt.where(color: 'red')</tt>.
|
59
79
|
#
|
60
80
|
# You should always pass a callable object to the scopes defined
|
61
|
-
# with
|
81
|
+
# with #scope. This ensures that the scope is re-evaluated each
|
62
82
|
# time it is called.
|
63
83
|
#
|
64
84
|
# Note that this is simply 'syntactic sugar' for defining an actual
|
@@ -71,14 +91,15 @@ module ActiveRecord
|
|
71
91
|
# end
|
72
92
|
#
|
73
93
|
# Unlike <tt>Shirt.find(...)</tt>, however, the object returned by
|
74
|
-
# <tt>Shirt.red</tt> is not an Array
|
75
|
-
#
|
76
|
-
#
|
94
|
+
# <tt>Shirt.red</tt> is not an Array but an ActiveRecord::Relation,
|
95
|
+
# which is composable with other scopes; it resembles the association object
|
96
|
+
# constructed by a {has_many}[rdoc-ref:Associations::ClassMethods#has_many]
|
97
|
+
# declaration. For instance, you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
|
77
98
|
# <tt>Shirt.red.where(size: 'small')</tt>. Also, just as with the
|
78
99
|
# association objects, named \scopes act like an Array, implementing
|
79
100
|
# Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>,
|
80
101
|
# and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if
|
81
|
-
# <tt>Shirt.red</tt> really was an
|
102
|
+
# <tt>Shirt.red</tt> really was an array.
|
82
103
|
#
|
83
104
|
# These named \scopes are composable. For instance,
|
84
105
|
# <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are
|
@@ -89,7 +110,8 @@ module ActiveRecord
|
|
89
110
|
#
|
90
111
|
# All scopes are available as class methods on the ActiveRecord::Base
|
91
112
|
# descendant upon which the \scopes were defined. But they are also
|
92
|
-
# available to
|
113
|
+
# available to {has_many}[rdoc-ref:Associations::ClassMethods#has_many]
|
114
|
+
# associations. If,
|
93
115
|
#
|
94
116
|
# class Person < ActiveRecord::Base
|
95
117
|
# has_many :shirts
|
@@ -98,8 +120,8 @@ module ActiveRecord
|
|
98
120
|
# then <tt>elton.shirts.red.dry_clean_only</tt> will return all of
|
99
121
|
# Elton's red, dry clean only shirts.
|
100
122
|
#
|
101
|
-
# \Named scopes can also have extensions, just as with
|
102
|
-
# declarations:
|
123
|
+
# \Named scopes can also have extensions, just as with
|
124
|
+
# {has_many}[rdoc-ref:Associations::ClassMethods#has_many] declarations:
|
103
125
|
#
|
104
126
|
# class Shirt < ActiveRecord::Base
|
105
127
|
# scope :red, -> { where(color: 'red') } do
|
@@ -140,7 +162,7 @@ module ActiveRecord
|
|
140
162
|
# Article.featured.titles
|
141
163
|
def scope(name, body, &block)
|
142
164
|
unless body.respond_to?(:call)
|
143
|
-
raise ArgumentError,
|
165
|
+
raise ArgumentError, "The scope body needs to be callable."
|
144
166
|
end
|
145
167
|
|
146
168
|
if dangerous_class_method?(name)
|
@@ -149,15 +171,42 @@ module ActiveRecord
|
|
149
171
|
"a class method with the same name."
|
150
172
|
end
|
151
173
|
|
152
|
-
|
174
|
+
if method_defined_within?(name, Relation)
|
175
|
+
raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
|
176
|
+
"on the model \"#{self.name}\", but ActiveRecord::Relation already defined " \
|
177
|
+
"an instance method with the same name."
|
178
|
+
end
|
153
179
|
|
154
|
-
|
155
|
-
|
156
|
-
scope = scope.extending(extension) if extension
|
180
|
+
valid_scope_name?(name)
|
181
|
+
extension = Module.new(&block) if block
|
157
182
|
|
158
|
-
|
183
|
+
if body.respond_to?(:to_proc)
|
184
|
+
singleton_class.send(:define_method, name) do |*args|
|
185
|
+
scope = all
|
186
|
+
scope = scope._exec_scope(*args, &body)
|
187
|
+
scope = scope.extending(extension) if extension
|
188
|
+
scope
|
189
|
+
end
|
190
|
+
else
|
191
|
+
singleton_class.send(:define_method, name) do |*args|
|
192
|
+
scope = all
|
193
|
+
scope = scope.scoping { body.call(*args) || scope }
|
194
|
+
scope = scope.extending(extension) if extension
|
195
|
+
scope
|
196
|
+
end
|
159
197
|
end
|
198
|
+
|
199
|
+
generate_relation_method(name)
|
160
200
|
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
def valid_scope_name?(name)
|
205
|
+
if respond_to?(name, true) && logger
|
206
|
+
logger.warn "Creating scope :#{name}. " \
|
207
|
+
"Overwriting existing method #{self.name}.#{name}."
|
208
|
+
end
|
209
|
+
end
|
161
210
|
end
|
162
211
|
end
|
163
212
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/per_thread_registry"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Scoping
|
@@ -9,25 +11,35 @@ module ActiveRecord
|
|
9
11
|
include Named
|
10
12
|
end
|
11
13
|
|
12
|
-
module ClassMethods
|
13
|
-
def current_scope
|
14
|
-
ScopeRegistry.value_for(:current_scope,
|
14
|
+
module ClassMethods # :nodoc:
|
15
|
+
def current_scope(skip_inherited_scope = false)
|
16
|
+
ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_scope=(scope)
|
20
|
+
ScopeRegistry.set_value_for(:current_scope, self, scope)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Collects attributes from scopes that should be applied when creating
|
24
|
+
# an AR instance for the particular class this is called on.
|
25
|
+
def scope_attributes
|
26
|
+
all.scope_for_create
|
15
27
|
end
|
16
28
|
|
17
|
-
|
18
|
-
|
29
|
+
# Are there attributes associated with this scope?
|
30
|
+
def scope_attributes?
|
31
|
+
current_scope
|
19
32
|
end
|
20
33
|
end
|
21
34
|
|
22
|
-
def populate_with_current_scope_attributes
|
35
|
+
def populate_with_current_scope_attributes # :nodoc:
|
23
36
|
return unless self.class.scope_attributes?
|
24
37
|
|
25
|
-
self.class.scope_attributes
|
26
|
-
|
27
|
-
end
|
38
|
+
attributes = self.class.scope_attributes
|
39
|
+
_assign_attributes(attributes) if attributes.any?
|
28
40
|
end
|
29
41
|
|
30
|
-
def initialize_internals_callback
|
42
|
+
def initialize_internals_callback # :nodoc:
|
31
43
|
super
|
32
44
|
populate_with_current_scope_attributes
|
33
45
|
end
|
@@ -42,18 +54,18 @@ module ActiveRecord
|
|
42
54
|
# following code:
|
43
55
|
#
|
44
56
|
# registry = ActiveRecord::Scoping::ScopeRegistry
|
45
|
-
# registry.set_value_for(:current_scope,
|
57
|
+
# registry.set_value_for(:current_scope, Board, some_new_scope)
|
46
58
|
#
|
47
59
|
# Now when you run:
|
48
60
|
#
|
49
|
-
# registry.value_for(:current_scope,
|
61
|
+
# registry.value_for(:current_scope, Board)
|
50
62
|
#
|
51
|
-
# You will obtain whatever was defined in +some_new_scope+. The
|
52
|
-
# and
|
63
|
+
# You will obtain whatever was defined in +some_new_scope+. The #value_for
|
64
|
+
# and #set_value_for methods are delegated to the current ScopeRegistry
|
53
65
|
# object, so the above example code can also be called as:
|
54
66
|
#
|
55
67
|
# ActiveRecord::Scoping::ScopeRegistry.set_value_for(:current_scope,
|
56
|
-
#
|
68
|
+
# Board, some_new_scope)
|
57
69
|
class ScopeRegistry # :nodoc:
|
58
70
|
extend ActiveSupport::PerThreadRegistry
|
59
71
|
|
@@ -63,25 +75,32 @@ module ActiveRecord
|
|
63
75
|
@registry = Hash.new { |hash, key| hash[key] = {} }
|
64
76
|
end
|
65
77
|
|
66
|
-
# Obtains the value for a given +
|
67
|
-
def value_for(scope_type,
|
78
|
+
# Obtains the value for a given +scope_type+ and +model+.
|
79
|
+
def value_for(scope_type, model, skip_inherited_scope = false)
|
68
80
|
raise_invalid_scope_type!(scope_type)
|
69
|
-
@registry[scope_type][
|
81
|
+
return @registry[scope_type][model.name] if skip_inherited_scope
|
82
|
+
klass = model
|
83
|
+
base = model.base_class
|
84
|
+
while klass <= base
|
85
|
+
value = @registry[scope_type][klass.name]
|
86
|
+
return value if value
|
87
|
+
klass = klass.superclass
|
88
|
+
end
|
70
89
|
end
|
71
90
|
|
72
|
-
# Sets the +value+ for a given +scope_type+ and +
|
73
|
-
def set_value_for(scope_type,
|
91
|
+
# Sets the +value+ for a given +scope_type+ and +model+.
|
92
|
+
def set_value_for(scope_type, model, value)
|
74
93
|
raise_invalid_scope_type!(scope_type)
|
75
|
-
@registry[scope_type][
|
94
|
+
@registry[scope_type][model.name] = value
|
76
95
|
end
|
77
96
|
|
78
97
|
private
|
79
98
|
|
80
|
-
|
81
|
-
|
82
|
-
|
99
|
+
def raise_invalid_scope_type!(scope_type)
|
100
|
+
if !VALID_SCOPE_TYPES.include?(scope_type)
|
101
|
+
raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
|
102
|
+
end
|
83
103
|
end
|
84
|
-
end
|
85
104
|
end
|
86
105
|
end
|
87
106
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module SecureToken
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Example using #has_secure_token
|
9
|
+
#
|
10
|
+
# # Schema: User(token:string, auth_token:string)
|
11
|
+
# class User < ActiveRecord::Base
|
12
|
+
# has_secure_token
|
13
|
+
# has_secure_token :auth_token
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# user = User.new
|
17
|
+
# user.save
|
18
|
+
# user.token # => "pX27zsMN2ViQKta1bGfLmVJE"
|
19
|
+
# user.auth_token # => "77TMHrHJFvFDwodq8w7Ev2m7"
|
20
|
+
# user.regenerate_token # => true
|
21
|
+
# user.regenerate_auth_token # => true
|
22
|
+
#
|
23
|
+
# <tt>SecureRandom::base58</tt> is used to generate the 24-character unique token, so collisions are highly unlikely.
|
24
|
+
#
|
25
|
+
# Note that it's still possible to generate a race condition in the database in the same way that
|
26
|
+
# {validates_uniqueness_of}[rdoc-ref:Validations::ClassMethods#validates_uniqueness_of] can.
|
27
|
+
# You're encouraged to add a unique index in the database to deal with this even more unlikely scenario.
|
28
|
+
def has_secure_token(attribute = :token)
|
29
|
+
# Load securerandom only when has_secure_token is used.
|
30
|
+
require "active_support/core_ext/securerandom"
|
31
|
+
define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token }
|
32
|
+
before_create { send("#{attribute}=", self.class.generate_unique_secure_token) unless send("#{attribute}?") }
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate_unique_secure_token
|
36
|
+
SecureRandom.base58(24)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord #:nodoc:
|
2
|
-
# = Active Record Serialization
|
4
|
+
# = Active Record \Serialization
|
3
5
|
module Serialization
|
4
6
|
extend ActiveSupport::Concern
|
5
7
|
include ActiveModel::Serializers::JSON
|
@@ -9,14 +11,12 @@ module ActiveRecord #:nodoc:
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def serializable_hash(options = nil)
|
12
|
-
options = options.try(:
|
14
|
+
options = options.try(:dup) || {}
|
13
15
|
|
14
|
-
options[:except] = Array(options[:except]).map
|
16
|
+
options[:except] = Array(options[:except]).map(&:to_s)
|
15
17
|
options[:except] |= Array(self.class.inheritance_column)
|
16
18
|
|
17
19
|
super(options)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
21
|
-
|
22
|
-
require 'active_record/serializers/xml_serializer'
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module ActiveRecord
|
3
4
|
# Statement cache is used to cache a single statement in order to avoid creating the AST again.
|
4
5
|
# Initializing the cache is done by passing the statement in the create block:
|
5
6
|
#
|
@@ -7,12 +8,14 @@ module ActiveRecord
|
|
7
8
|
# Book.where(name: "my book").where("author_id > 3")
|
8
9
|
# end
|
9
10
|
#
|
10
|
-
# The cached statement is executed by using the
|
11
|
+
# The cached statement is executed by using the
|
12
|
+
# {connection.execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute] method:
|
11
13
|
#
|
12
|
-
# cache.execute([], Book
|
14
|
+
# cache.execute([], Book.connection)
|
13
15
|
#
|
14
|
-
# The relation returned by the block is cached, and for each
|
15
|
-
#
|
16
|
+
# The relation returned by the block is cached, and for each
|
17
|
+
# {execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute]
|
18
|
+
# call the cached relation gets duped. Database is queried when +to_a+ is called on the relation.
|
16
19
|
#
|
17
20
|
# If you want to cache the statement without the values you can use the +bind+ method of the
|
18
21
|
# block parameter.
|
@@ -23,7 +26,7 @@ module ActiveRecord
|
|
23
26
|
#
|
24
27
|
# And pass the bind values as the first argument of +execute+ call.
|
25
28
|
#
|
26
|
-
# cache.execute(["my book"], Book
|
29
|
+
# cache.execute(["my book"], Book.connection)
|
27
30
|
class StatementCache # :nodoc:
|
28
31
|
class Substitute; end # :nodoc:
|
29
32
|
|
@@ -38,28 +41,27 @@ module ActiveRecord
|
|
38
41
|
end
|
39
42
|
|
40
43
|
class PartialQuery < Query # :nodoc:
|
41
|
-
def initialize
|
44
|
+
def initialize(values)
|
42
45
|
@values = values
|
43
|
-
@indexes = values.each_with_index.find_all { |thing,i|
|
46
|
+
@indexes = values.each_with_index.find_all { |thing, i|
|
44
47
|
Arel::Nodes::BindParam === thing
|
45
48
|
}.map(&:last)
|
46
49
|
end
|
47
50
|
|
48
51
|
def sql_for(binds, connection)
|
49
52
|
val = @values.dup
|
50
|
-
|
51
|
-
@indexes.each { |i| val[i] = connection.quote(
|
53
|
+
casted_binds = binds.map(&:value_for_database)
|
54
|
+
@indexes.each { |i| val[i] = connection.quote(casted_binds.shift) }
|
52
55
|
val.join
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
56
|
-
def self.query(
|
57
|
-
Query.new
|
59
|
+
def self.query(sql)
|
60
|
+
Query.new(sql)
|
58
61
|
end
|
59
62
|
|
60
|
-
def self.partial_query(
|
61
|
-
|
62
|
-
PartialQuery.new collected
|
63
|
+
def self.partial_query(values)
|
64
|
+
PartialQuery.new(values)
|
63
65
|
end
|
64
66
|
|
65
67
|
class Params # :nodoc:
|
@@ -67,45 +69,53 @@ module ActiveRecord
|
|
67
69
|
end
|
68
70
|
|
69
71
|
class BindMap # :nodoc:
|
70
|
-
def initialize(
|
71
|
-
@indexes
|
72
|
-
@
|
72
|
+
def initialize(bound_attributes)
|
73
|
+
@indexes = []
|
74
|
+
@bound_attributes = bound_attributes
|
73
75
|
|
74
|
-
|
75
|
-
if Substitute === value
|
76
|
+
bound_attributes.each_with_index do |attr, i|
|
77
|
+
if Substitute === attr.value
|
76
78
|
@indexes << i
|
77
79
|
end
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
83
|
def bind(values)
|
82
|
-
|
83
|
-
@indexes.each_with_index { |offset,i|
|
84
|
-
|
84
|
+
bas = @bound_attributes.dup
|
85
|
+
@indexes.each_with_index { |offset, i| bas[offset] = bas[offset].with_cast_value(values[i]) }
|
86
|
+
bas
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
bind_map
|
93
|
-
query_builder = connection.cacheable_query relation.arel
|
94
|
-
new query_builder, bind_map
|
90
|
+
def self.create(connection, callable = nil, &block)
|
91
|
+
relation = (callable || block).call Params.new
|
92
|
+
query_builder, binds = connection.cacheable_query(self, relation.arel)
|
93
|
+
bind_map = BindMap.new(binds)
|
94
|
+
new(query_builder, bind_map, relation.klass)
|
95
95
|
end
|
96
96
|
|
97
|
-
def initialize(query_builder, bind_map)
|
97
|
+
def initialize(query_builder, bind_map, klass)
|
98
98
|
@query_builder = query_builder
|
99
|
-
@bind_map
|
99
|
+
@bind_map = bind_map
|
100
|
+
@klass = klass
|
100
101
|
end
|
101
102
|
|
102
|
-
def execute(params,
|
103
|
+
def execute(params, connection, &block)
|
103
104
|
bind_values = bind_map.bind params
|
104
105
|
|
105
106
|
sql = query_builder.sql_for bind_values, connection
|
106
107
|
|
107
|
-
klass.find_by_sql
|
108
|
+
klass.find_by_sql(sql, bind_values, preparable: true, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.unsupported_value?(value)
|
112
|
+
case value
|
113
|
+
when NilClass, Array, Range, Hash, Relation, Base then true
|
114
|
+
end
|
108
115
|
end
|
109
|
-
|
116
|
+
|
117
|
+
protected
|
118
|
+
|
119
|
+
attr_reader :query_builder, :bind_map, :klass
|
110
120
|
end
|
111
121
|
end
|
data/lib/active_record/store.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
# Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column.
|
@@ -15,11 +17,16 @@ module ActiveRecord
|
|
15
17
|
# You can set custom coder to encode/decode your serialized attributes to/from different formats.
|
16
18
|
# JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
|
17
19
|
#
|
18
|
-
# NOTE
|
19
|
-
# the serialization provided by
|
20
|
+
# NOTE: If you are using PostgreSQL specific columns like +hstore+ or +json+ there is no need for
|
21
|
+
# the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
|
22
|
+
# Simply use {.store_accessor}[rdoc-ref:ClassMethods#store_accessor] instead to generate
|
20
23
|
# the accessor methods. Be aware that these columns use a string keyed hash and do not allow access
|
21
24
|
# using a symbol.
|
22
25
|
#
|
26
|
+
# NOTE: The default validations with the exception of +uniqueness+ will work.
|
27
|
+
# For example, if you want to check for +uniqueness+ with +hstore+ you will
|
28
|
+
# need to use a custom validation to handle it.
|
29
|
+
#
|
23
30
|
# Examples:
|
24
31
|
#
|
25
32
|
# class User < ActiveRecord::Base
|
@@ -39,7 +46,7 @@ module ActiveRecord
|
|
39
46
|
# store_accessor :settings, :privileges, :servants
|
40
47
|
# end
|
41
48
|
#
|
42
|
-
# The stored attribute names can be retrieved using
|
49
|
+
# The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
|
43
50
|
#
|
44
51
|
# User.stored_attributes[:settings] # [:color, :homepage]
|
45
52
|
#
|
@@ -73,7 +80,7 @@ module ActiveRecord
|
|
73
80
|
|
74
81
|
module ClassMethods
|
75
82
|
def store(store_attribute, options = {})
|
76
|
-
serialize store_attribute, IndifferentCoder.new(options[:coder])
|
83
|
+
serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder])
|
77
84
|
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
|
78
85
|
end
|
79
86
|
|
@@ -109,27 +116,26 @@ module ActiveRecord
|
|
109
116
|
|
110
117
|
def stored_attributes
|
111
118
|
parent = superclass.respond_to?(:stored_attributes) ? superclass.stored_attributes : {}
|
112
|
-
if
|
113
|
-
parent.merge!(
|
119
|
+
if local_stored_attributes
|
120
|
+
parent.merge!(local_stored_attributes) { |k, a, b| a | b }
|
114
121
|
end
|
115
122
|
parent
|
116
123
|
end
|
117
124
|
end
|
118
125
|
|
119
|
-
|
120
|
-
def read_store_attribute(store_attribute, key)
|
126
|
+
private
|
127
|
+
def read_store_attribute(store_attribute, key) # :doc:
|
121
128
|
accessor = store_accessor_for(store_attribute)
|
122
129
|
accessor.read(self, store_attribute, key)
|
123
130
|
end
|
124
131
|
|
125
|
-
def write_store_attribute(store_attribute, key, value)
|
132
|
+
def write_store_attribute(store_attribute, key, value) # :doc:
|
126
133
|
accessor = store_accessor_for(store_attribute)
|
127
134
|
accessor.write(self, store_attribute, key, value)
|
128
135
|
end
|
129
136
|
|
130
|
-
private
|
131
137
|
def store_accessor_for(store_attribute)
|
132
|
-
type_for_attribute(store_attribute
|
138
|
+
type_for_attribute(store_attribute).accessor
|
133
139
|
end
|
134
140
|
|
135
141
|
class HashAccessor # :nodoc:
|
@@ -172,34 +178,34 @@ module ActiveRecord
|
|
172
178
|
end
|
173
179
|
end
|
174
180
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
181
|
+
class IndifferentCoder # :nodoc:
|
182
|
+
def initialize(attr_name, coder_or_class_name)
|
183
|
+
@coder =
|
184
|
+
if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
|
185
|
+
coder_or_class_name
|
186
|
+
else
|
187
|
+
ActiveRecord::Coders::YAMLColumn.new(attr_name, coder_or_class_name || Object)
|
188
|
+
end
|
189
|
+
end
|
184
190
|
|
185
|
-
|
186
|
-
|
187
|
-
|
191
|
+
def dump(obj)
|
192
|
+
@coder.dump self.class.as_indifferent_hash(obj)
|
193
|
+
end
|
188
194
|
|
189
|
-
|
190
|
-
|
191
|
-
|
195
|
+
def load(yaml)
|
196
|
+
self.class.as_indifferent_hash(@coder.load(yaml || ""))
|
197
|
+
end
|
192
198
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
199
|
+
def self.as_indifferent_hash(obj)
|
200
|
+
case obj
|
201
|
+
when ActiveSupport::HashWithIndifferentAccess
|
202
|
+
obj
|
203
|
+
when Hash
|
204
|
+
obj.with_indifferent_access
|
205
|
+
else
|
206
|
+
ActiveSupport::HashWithIndifferentAccess.new
|
207
|
+
end
|
201
208
|
end
|
202
209
|
end
|
203
|
-
end
|
204
210
|
end
|
205
211
|
end
|