activerecord 5.0.7 → 5.1.7
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 +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_record/attribute"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class Attribute # :nodoc:
|
@@ -20,9 +20,11 @@ module ActiveRecord
|
|
20
20
|
self.class.new(name, user_provided_value, type, original_attribute)
|
21
21
|
end
|
22
22
|
|
23
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
24
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
23
25
|
protected
|
24
26
|
|
25
|
-
|
27
|
+
attr_reader :user_provided_value
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
@@ -77,7 +77,11 @@ module ActiveRecord
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def with_type(type)
|
80
|
-
|
80
|
+
if changed_in_place?
|
81
|
+
with_value_from_user(value).with_type(type)
|
82
|
+
else
|
83
|
+
self.class.new(name, value_before_type_cast, type, original_attribute)
|
84
|
+
end
|
81
85
|
end
|
82
86
|
|
83
87
|
def type_cast(*)
|
@@ -108,106 +112,129 @@ module ActiveRecord
|
|
108
112
|
[self.class, name, value_before_type_cast, type].hash
|
109
113
|
end
|
110
114
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
if defined?(@value) && @value.duplicable?
|
118
|
-
@value = @value.dup
|
119
|
-
end
|
115
|
+
def init_with(coder)
|
116
|
+
@name = coder["name"]
|
117
|
+
@value_before_type_cast = coder["value_before_type_cast"]
|
118
|
+
@type = coder["type"]
|
119
|
+
@original_attribute = coder["original_attribute"]
|
120
|
+
@value = coder["value"] if coder.map.key?("value")
|
120
121
|
end
|
121
122
|
|
122
|
-
def
|
123
|
-
|
123
|
+
def encode_with(coder)
|
124
|
+
coder["name"] = name
|
125
|
+
coder["value_before_type_cast"] = value_before_type_cast unless value_before_type_cast.nil?
|
126
|
+
coder["type"] = type if type
|
127
|
+
coder["original_attribute"] = original_attribute if original_attribute
|
128
|
+
coder["value"] = value if defined?(@value)
|
124
129
|
end
|
125
130
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
else
|
130
|
-
_original_value_for_database
|
131
|
-
end
|
132
|
-
end
|
131
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
132
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
133
|
+
protected
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
end
|
135
|
+
attr_reader :original_attribute
|
136
|
+
alias_method :assigned?, :original_attribute
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
|
138
|
+
def original_value_for_database
|
139
|
+
if assigned?
|
140
|
+
original_attribute.original_value_for_database
|
141
|
+
else
|
142
|
+
_original_value_for_database
|
143
|
+
end
|
141
144
|
end
|
142
145
|
|
143
|
-
|
144
|
-
|
146
|
+
private
|
147
|
+
def initialize_dup(other)
|
148
|
+
if defined?(@value) && @value.duplicable?
|
149
|
+
@value = @value.dup
|
150
|
+
end
|
145
151
|
end
|
146
|
-
end
|
147
152
|
|
148
|
-
|
149
|
-
|
150
|
-
type.cast(value)
|
153
|
+
def changed_from_assignment?
|
154
|
+
assigned? && type.changed?(original_value, value, value_before_type_cast)
|
151
155
|
end
|
152
156
|
|
153
|
-
def
|
154
|
-
|
157
|
+
def _original_value_for_database
|
158
|
+
type.serialize(original_value)
|
155
159
|
end
|
156
|
-
end
|
157
160
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
161
|
+
class FromDatabase < Attribute # :nodoc:
|
162
|
+
def type_cast(value)
|
163
|
+
type.deserialize(value)
|
164
|
+
end
|
162
165
|
|
163
|
-
|
164
|
-
|
166
|
+
def _original_value_for_database
|
167
|
+
value_before_type_cast
|
168
|
+
end
|
165
169
|
end
|
166
|
-
end
|
167
170
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
171
|
+
class FromUser < Attribute # :nodoc:
|
172
|
+
def type_cast(value)
|
173
|
+
type.cast(value)
|
174
|
+
end
|
172
175
|
|
173
|
-
|
174
|
-
|
176
|
+
def came_from_user?
|
177
|
+
true
|
178
|
+
end
|
175
179
|
end
|
176
180
|
|
177
|
-
|
178
|
-
|
179
|
-
|
181
|
+
class WithCastValue < Attribute # :nodoc:
|
182
|
+
def type_cast(value)
|
183
|
+
value
|
184
|
+
end
|
180
185
|
|
181
|
-
|
182
|
-
|
186
|
+
def changed_in_place?
|
187
|
+
false
|
188
|
+
end
|
183
189
|
end
|
184
|
-
alias_method :with_value_from_user, :with_value_from_database
|
185
|
-
end
|
186
190
|
|
187
|
-
|
188
|
-
|
191
|
+
class Null < Attribute # :nodoc:
|
192
|
+
def initialize(name)
|
193
|
+
super(name, nil, Type.default_value)
|
194
|
+
end
|
189
195
|
|
190
|
-
|
191
|
-
|
192
|
-
|
196
|
+
def type_cast(*)
|
197
|
+
nil
|
198
|
+
end
|
193
199
|
|
194
|
-
|
195
|
-
|
196
|
-
yield name
|
200
|
+
def with_type(type)
|
201
|
+
self.class.with_cast_value(name, nil, type)
|
197
202
|
end
|
198
|
-
end
|
199
203
|
|
200
|
-
|
201
|
-
|
204
|
+
def with_value_from_database(value)
|
205
|
+
raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
|
206
|
+
end
|
207
|
+
alias_method :with_value_from_user, :with_value_from_database
|
202
208
|
end
|
203
209
|
|
204
|
-
|
205
|
-
|
210
|
+
class Uninitialized < Attribute # :nodoc:
|
211
|
+
UNINITIALIZED_ORIGINAL_VALUE = Object.new
|
206
212
|
|
207
|
-
|
208
|
-
|
213
|
+
def initialize(name, type)
|
214
|
+
super(name, nil, type)
|
215
|
+
end
|
216
|
+
|
217
|
+
def value
|
218
|
+
if block_given?
|
219
|
+
yield name
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def original_value
|
224
|
+
UNINITIALIZED_ORIGINAL_VALUE
|
225
|
+
end
|
226
|
+
|
227
|
+
def value_for_database
|
228
|
+
end
|
229
|
+
|
230
|
+
def initialized?
|
231
|
+
false
|
232
|
+
end
|
233
|
+
|
234
|
+
def with_type(type)
|
235
|
+
self.class.new(name, type)
|
236
|
+
end
|
209
237
|
end
|
210
|
-
|
211
|
-
private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
|
238
|
+
private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
|
212
239
|
end
|
213
240
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_model/forbidden_attributes_protection"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module AttributeAssignment
|
@@ -12,80 +12,80 @@ module ActiveRecord
|
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def _assign_attributes(attributes)
|
16
|
+
multi_parameter_attributes = {}
|
17
|
+
nested_parameter_attributes = {}
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
attributes.each do |k, v|
|
20
|
+
if k.include?("(")
|
21
|
+
multi_parameter_attributes[k] = attributes.delete(k)
|
22
|
+
elsif v.is_a?(Hash)
|
23
|
+
nested_parameter_attributes[k] = attributes.delete(k)
|
24
|
+
end
|
24
25
|
end
|
25
|
-
|
26
|
-
super(attributes)
|
26
|
+
super(attributes)
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty?
|
29
|
+
assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty?
|
30
|
+
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
# Assign any deferred nested attributes after the base attributes have been set.
|
33
|
+
def assign_nested_parameter_attributes(pairs)
|
34
|
+
pairs.each { |k, v| _assign_attribute(k, v) }
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
37
|
+
# Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
|
38
|
+
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
|
39
|
+
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
|
40
|
+
# written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
|
41
|
+
# parentheses to have the parameters typecasted before they're used in the constructor. Use i for Integer and
|
42
|
+
# f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+.
|
43
|
+
def assign_multiparameter_attributes(pairs)
|
44
|
+
execute_callstack_for_multiparameter_attributes(
|
45
|
+
extract_callstack_for_multiparameter_attributes(pairs)
|
46
|
+
)
|
47
|
+
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
def execute_callstack_for_multiparameter_attributes(callstack)
|
50
|
+
errors = []
|
51
|
+
callstack.each do |name, values_with_empty_parameters|
|
52
|
+
begin
|
53
|
+
if values_with_empty_parameters.each_value.all?(&:nil?)
|
54
|
+
values = nil
|
55
|
+
else
|
56
|
+
values = values_with_empty_parameters
|
57
|
+
end
|
58
|
+
send("#{name}=", values)
|
59
|
+
rescue => ex
|
60
|
+
errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
|
57
61
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
62
|
+
end
|
63
|
+
unless errors.empty?
|
64
|
+
error_descriptions = errors.map(&:message).join(",")
|
65
|
+
raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
|
61
66
|
end
|
62
67
|
end
|
63
|
-
unless errors.empty?
|
64
|
-
error_descriptions = errors.map(&:message).join(",")
|
65
|
-
raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
|
66
|
-
end
|
67
|
-
end
|
68
68
|
|
69
|
-
|
70
|
-
|
69
|
+
def extract_callstack_for_multiparameter_attributes(pairs)
|
70
|
+
attributes = {}
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
pairs.each do |(multiparameter_name, value)|
|
73
|
+
attribute_name = multiparameter_name.split("(").first
|
74
|
+
attributes[attribute_name] ||= {}
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
|
77
|
+
attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value
|
78
|
+
end
|
79
79
|
|
80
|
-
|
81
|
-
|
80
|
+
attributes
|
81
|
+
end
|
82
82
|
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
def type_cast_attribute_value(multiparameter_name, value)
|
84
|
+
multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
|
85
|
+
end
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
def find_parameter_position(multiparameter_name)
|
88
|
+
multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
|
89
|
+
end
|
90
90
|
end
|
91
91
|
end
|
@@ -8,12 +8,34 @@ module ActiveRecord
|
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods # :nodoc:
|
11
|
+
# This method is an internal API used to create class macros such as
|
12
|
+
# +serialize+, and features like time zone aware attributes.
|
13
|
+
#
|
14
|
+
# Used to wrap the type of an attribute in a new type.
|
15
|
+
# When the schema for a model is loaded, attributes with the same name as
|
16
|
+
# +column_name+ will have their type yielded to the given block. The
|
17
|
+
# return value of that block will be used instead.
|
18
|
+
#
|
19
|
+
# Subsequent calls where +column_name+ and +decorator_name+ are the same
|
20
|
+
# will override the previous decorator, not decorate twice. This can be
|
21
|
+
# used to create idempotent class macros like +serialize+
|
11
22
|
def decorate_attribute_type(column_name, decorator_name, &block)
|
12
23
|
matcher = ->(name, _) { name == column_name.to_s }
|
13
24
|
key = "_#{column_name}_#{decorator_name}"
|
14
25
|
decorate_matching_attribute_types(matcher, key, &block)
|
15
26
|
end
|
16
27
|
|
28
|
+
# This method is an internal API used to create higher level features like
|
29
|
+
# time zone aware attributes.
|
30
|
+
#
|
31
|
+
# When the schema for a model is loaded, +matcher+ will be called for each
|
32
|
+
# attribute with its name and type. If the matcher returns a truthy value,
|
33
|
+
# the type will then be yielded to the given block, and the return value
|
34
|
+
# of that block will replace the type.
|
35
|
+
#
|
36
|
+
# Subsequent calls to this method with the same value for +decorator_name+
|
37
|
+
# will replace the previous decorator, not decorate twice. This can be
|
38
|
+
# used to ensure that class macros are idempotent.
|
17
39
|
def decorate_matching_attribute_types(matcher, decorator_name, &block)
|
18
40
|
reload_schema_from_cache
|
19
41
|
decorator_name = decorator_name.to_s
|
@@ -24,13 +46,13 @@ module ActiveRecord
|
|
24
46
|
|
25
47
|
private
|
26
48
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
49
|
+
def load_schema!
|
50
|
+
super
|
51
|
+
attribute_types.each do |name, type|
|
52
|
+
decorated_type = attribute_type_decorations.apply(name, type)
|
53
|
+
define_attribute(name, decorated_type)
|
54
|
+
end
|
32
55
|
end
|
33
|
-
end
|
34
56
|
end
|
35
57
|
|
36
58
|
class TypeDecorator # :nodoc:
|
@@ -53,15 +75,15 @@ module ActiveRecord
|
|
53
75
|
|
54
76
|
private
|
55
77
|
|
56
|
-
|
57
|
-
|
58
|
-
|
78
|
+
def decorators_for(name, type)
|
79
|
+
matching(name, type).map(&:last)
|
80
|
+
end
|
59
81
|
|
60
|
-
|
61
|
-
|
62
|
-
|
82
|
+
def matching(name, type)
|
83
|
+
@decorations.values.select do |(matcher, _)|
|
84
|
+
matcher.call(name, type)
|
85
|
+
end
|
63
86
|
end
|
64
|
-
end
|
65
87
|
end
|
66
88
|
end
|
67
89
|
end
|
@@ -63,14 +63,14 @@ module ActiveRecord
|
|
63
63
|
|
64
64
|
private
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
# Handle *_before_type_cast for method_missing.
|
67
|
+
def attribute_before_type_cast(attribute_name)
|
68
|
+
read_attribute_before_type_cast(attribute_name)
|
69
|
+
end
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
def attribute_came_from_user?(attribute_name)
|
72
|
+
@attributes[attribute_name].came_from_user?
|
73
|
+
end
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|