activerecord 4.0.4 → 4.1.16
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 +4 -4
- data/CHANGELOG.md +1632 -1797
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +49 -29
- data/lib/active_record/associations/association.rb +9 -17
- data/lib/active_record/associations/association_scope.rb +59 -49
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
- data/lib/active_record/associations/builder/association.rb +84 -54
- data/lib/active_record/associations/builder/belongs_to.rb +90 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
- data/lib/active_record/associations/builder/has_many.rb +3 -3
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +121 -111
- data/lib/active_record/associations/collection_proxy.rb +73 -18
- data/lib/active_record/associations/has_many_association.rb +14 -11
- data/lib/active_record/associations/has_many_through_association.rb +33 -6
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_dependency.rb +208 -168
- data/lib/active_record/associations/preloader/association.rb +69 -27
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/preloader.rb +63 -49
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +30 -9
- data/lib/active_record/associations.rb +116 -42
- data/lib/active_record/attribute_assignment.rb +6 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +35 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -1
- data/lib/active_record/attribute_methods/read.rb +56 -29
- data/lib/active_record/attribute_methods/serialization.rb +44 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
- data/lib/active_record/attribute_methods/write.rb +59 -26
- data/lib/active_record/attribute_methods.rb +82 -43
- data/lib/active_record/autosave_association.rb +209 -194
- data/lib/active_record/base.rb +6 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
- data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
- data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
- data/lib/active_record/connection_handling.rb +39 -5
- data/lib/active_record/core.rb +38 -54
- data/lib/active_record/counter_cache.rb +9 -10
- data/lib/active_record/dynamic_matchers.rb +6 -2
- data/lib/active_record/enum.rb +199 -0
- data/lib/active_record/errors.rb +22 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +173 -76
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +23 -9
- data/lib/active_record/integration.rb +54 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +6 -13
- data/lib/active_record/migration/command_recorder.rb +8 -2
- data/lib/active_record/migration.rb +91 -56
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +25 -13
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +26 -6
- data/lib/active_record/persistence.rb +23 -29
- data/lib/active_record/querying.rb +15 -12
- data/lib/active_record/railtie.rb +12 -61
- data/lib/active_record/railties/databases.rake +37 -56
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +230 -79
- data/lib/active_record/relation/batches.rb +74 -24
- data/lib/active_record/relation/calculations.rb +52 -48
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +210 -67
- data/lib/active_record/relation/merger.rb +15 -12
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder.rb +81 -40
- data/lib/active_record/relation/query_methods.rb +185 -108
- data/lib/active_record/relation/spawn_methods.rb +8 -5
- data/lib/active_record/relation.rb +79 -84
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +4 -4
- data/lib/active_record/schema_dumper.rb +18 -6
- data/lib/active_record/schema_migration.rb +31 -18
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +14 -29
- data/lib/active_record/scoping.rb +5 -0
- data/lib/active_record/store.rb +67 -18
- data/lib/active_record/tasks/database_tasks.rb +66 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/transactions.rb +10 -12
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +19 -9
- data/lib/active_record/version.rb +4 -7
- data/lib/active_record.rb +5 -7
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- data/lib/rails/generators/active_record.rb +2 -8
- metadata +18 -30
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/join_helper.rb +0 -45
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -96
@@ -2,7 +2,6 @@ module ActiveRecord
|
|
2
2
|
module Associations
|
3
3
|
class Preloader
|
4
4
|
module ThroughAssociation #:nodoc:
|
5
|
-
|
6
5
|
def through_reflection
|
7
6
|
reflection.through_reflection
|
8
7
|
end
|
@@ -11,51 +10,84 @@ module ActiveRecord
|
|
11
10
|
reflection.source_reflection
|
12
11
|
end
|
13
12
|
|
14
|
-
def associated_records_by_owner
|
15
|
-
|
13
|
+
def associated_records_by_owner(preloader)
|
14
|
+
preloader.preload(owners,
|
15
|
+
through_reflection.name,
|
16
|
+
through_scope)
|
16
17
|
|
17
|
-
|
18
|
+
through_records = owners.map do |owner|
|
19
|
+
association = owner.association through_reflection.name
|
18
20
|
|
19
|
-
|
20
|
-
records.map! { |r| r.send(source_reflection.name) }.flatten!
|
21
|
-
records.compact!
|
21
|
+
[owner, Array(association.reader)]
|
22
22
|
end
|
23
|
-
end
|
24
23
|
|
25
|
-
|
24
|
+
reset_association owners, through_reflection.name
|
25
|
+
|
26
|
+
middle_records = through_records.map { |(_,rec)| rec }.flatten
|
27
|
+
|
28
|
+
preloaders = preloader.preload(middle_records,
|
29
|
+
source_reflection.name,
|
30
|
+
reflection_scope)
|
26
31
|
|
27
|
-
|
28
|
-
|
32
|
+
@preloaded_records = preloaders.flat_map(&:preloaded_records)
|
33
|
+
|
34
|
+
middle_to_pl = preloaders.each_with_object({}) do |pl,h|
|
35
|
+
pl.owners.each { |middle|
|
36
|
+
h[middle] = pl
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
record_offset = {}
|
41
|
+
@preloaded_records.each_with_index do |record,i|
|
42
|
+
record_offset[record] = i
|
43
|
+
end
|
29
44
|
|
30
|
-
|
31
|
-
|
45
|
+
through_records.each_with_object({}) { |(lhs,center),records_by_owner|
|
46
|
+
pl_to_middle = center.group_by { |record| middle_to_pl[record] }
|
32
47
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
48
|
+
records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
|
49
|
+
rhs_records = middles.flat_map { |r|
|
50
|
+
association = r.association source_reflection.name
|
51
|
+
|
52
|
+
association.reader
|
53
|
+
}.compact
|
54
|
+
|
55
|
+
rhs_records.sort_by { |rhs| record_offset[rhs] }
|
37
56
|
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def reset_association(owners, association_name)
|
63
|
+
should_reset = (through_scope != through_reflection.klass.unscoped) ||
|
64
|
+
(reflection.options[:source_type] && through_reflection.collection?)
|
38
65
|
|
39
|
-
|
40
|
-
|
66
|
+
# Dont cache the association - we would only be caching a subset
|
67
|
+
if should_reset
|
68
|
+
owners.each { |owner|
|
69
|
+
owner.association(association_name).reset
|
70
|
+
}
|
71
|
+
end
|
41
72
|
end
|
42
73
|
|
74
|
+
|
43
75
|
def through_scope
|
44
|
-
|
76
|
+
scope = through_reflection.klass.unscoped
|
45
77
|
|
46
78
|
if options[:source_type]
|
47
|
-
|
79
|
+
scope.where! reflection.foreign_type => options[:source_type]
|
48
80
|
else
|
49
81
|
unless reflection_scope.where_values.empty?
|
50
|
-
|
51
|
-
|
82
|
+
scope.includes_values = Array(reflection_scope.values[:includes] || options[:source])
|
83
|
+
scope.where_values = reflection_scope.values[:where]
|
52
84
|
end
|
53
85
|
|
54
|
-
|
55
|
-
|
86
|
+
scope.references! reflection_scope.values[:references]
|
87
|
+
scope.order! reflection_scope.values[:order] if scope.eager_loading?
|
56
88
|
end
|
57
89
|
|
58
|
-
|
90
|
+
scope
|
59
91
|
end
|
60
92
|
end
|
61
93
|
end
|
@@ -42,12 +42,9 @@ module ActiveRecord
|
|
42
42
|
autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
|
43
43
|
autoload :HasOne, 'active_record/associations/preloader/has_one'
|
44
44
|
autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
|
45
|
-
autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
|
46
45
|
autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
|
47
46
|
end
|
48
47
|
|
49
|
-
attr_reader :records, :associations, :preload_scope, :model
|
50
|
-
|
51
48
|
# Eager loads the named associations for the given Active Record record(s).
|
52
49
|
#
|
53
50
|
# In this description, 'association name' shall refer to the name passed
|
@@ -82,38 +79,48 @@ module ActiveRecord
|
|
82
79
|
# [ :books, :author ]
|
83
80
|
# { author: :avatar }
|
84
81
|
# [ :books, { author: :avatar } ]
|
85
|
-
def initialize(records, associations, preload_scope = nil)
|
86
|
-
@records = Array.wrap(records).compact.uniq
|
87
|
-
@associations = Array.wrap(associations)
|
88
|
-
@preload_scope = preload_scope || Relation.new(nil, nil)
|
89
|
-
end
|
90
82
|
|
91
|
-
|
92
|
-
|
93
|
-
|
83
|
+
NULL_RELATION = Struct.new(:values).new({})
|
84
|
+
|
85
|
+
def preload(records, associations, preload_scope = nil)
|
86
|
+
records = Array.wrap(records).compact.uniq
|
87
|
+
associations = Array.wrap(associations)
|
88
|
+
preload_scope = preload_scope || NULL_RELATION
|
89
|
+
|
90
|
+
if records.empty?
|
91
|
+
[]
|
92
|
+
else
|
93
|
+
associations.flat_map { |association|
|
94
|
+
preloaders_on association, records, preload_scope
|
95
|
+
}
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
97
99
|
private
|
98
100
|
|
99
|
-
def
|
101
|
+
def preloaders_on(association, records, scope)
|
100
102
|
case association
|
101
103
|
when Hash
|
102
|
-
|
104
|
+
preloaders_for_hash(association, records, scope)
|
103
105
|
when Symbol
|
104
|
-
|
106
|
+
preloaders_for_one(association, records, scope)
|
105
107
|
when String
|
106
|
-
|
108
|
+
preloaders_for_one(association.to_sym, records, scope)
|
107
109
|
else
|
108
110
|
raise ArgumentError, "#{association.inspect} was not recognised for preload"
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
112
|
-
def
|
113
|
-
association.
|
114
|
-
|
115
|
-
|
116
|
-
|
114
|
+
def preloaders_for_hash(association, records, scope)
|
115
|
+
association.flat_map { |parent, child|
|
116
|
+
loaders = preloaders_for_one parent, records, scope
|
117
|
+
|
118
|
+
recs = loaders.flat_map(&:preloaded_records).uniq
|
119
|
+
loaders.concat Array.wrap(child).flat_map { |assoc|
|
120
|
+
preloaders_on assoc, recs, scope
|
121
|
+
}
|
122
|
+
loaders
|
123
|
+
}
|
117
124
|
end
|
118
125
|
|
119
126
|
# Not all records have the same class, so group then preload group on the reflection
|
@@ -123,53 +130,60 @@ module ActiveRecord
|
|
123
130
|
# Additionally, polymorphic belongs_to associations can have multiple associated
|
124
131
|
# classes, depending on the polymorphic_type field. So we group by the classes as
|
125
132
|
# well.
|
126
|
-
def
|
127
|
-
grouped_records(association).
|
128
|
-
klasses.
|
129
|
-
preloader_for(reflection).new(
|
133
|
+
def preloaders_for_one(association, records, scope)
|
134
|
+
grouped_records(association, records).flat_map do |reflection, klasses|
|
135
|
+
klasses.map do |rhs_klass, rs|
|
136
|
+
loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope)
|
137
|
+
loader.run self
|
138
|
+
loader
|
130
139
|
end
|
131
140
|
end
|
132
141
|
end
|
133
142
|
|
134
|
-
def grouped_records(association)
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
143
|
+
def grouped_records(association, records)
|
144
|
+
h = {}
|
145
|
+
records.each do |record|
|
146
|
+
next unless record
|
147
|
+
assoc = record.association(association)
|
148
|
+
klasses = h[assoc.reflection] ||= {}
|
149
|
+
(klasses[assoc.klass] ||= []) << record
|
150
|
+
end
|
151
|
+
h
|
140
152
|
end
|
141
153
|
|
142
|
-
|
143
|
-
|
144
|
-
record_class = record.class
|
145
|
-
reflection = record_class.reflections[association]
|
154
|
+
class AlreadyLoaded
|
155
|
+
attr_reader :owners, :reflection
|
146
156
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
157
|
+
def initialize(klass, owners, reflection, preload_scope)
|
158
|
+
@owners = owners
|
159
|
+
@reflection = reflection
|
160
|
+
end
|
151
161
|
|
152
|
-
|
162
|
+
def run(preloader); end
|
163
|
+
|
164
|
+
def preloaded_records
|
165
|
+
owners.flat_map { |owner| owner.association(reflection.name).target }
|
153
166
|
end
|
154
167
|
end
|
155
168
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
else
|
161
|
-
reflection.klass
|
162
|
-
end
|
169
|
+
class NullPreloader
|
170
|
+
def self.new(klass, owners, reflection, preload_scope); self; end
|
171
|
+
def self.run(preloader); end
|
172
|
+
def self.preloaded_records; []; end
|
163
173
|
end
|
164
174
|
|
165
|
-
def preloader_for(reflection)
|
175
|
+
def preloader_for(reflection, owners, rhs_klass)
|
176
|
+
return NullPreloader unless rhs_klass
|
177
|
+
|
178
|
+
if owners.first.association(reflection.name).loaded?
|
179
|
+
return AlreadyLoaded
|
180
|
+
end
|
181
|
+
|
166
182
|
case reflection.macro
|
167
183
|
when :has_many
|
168
184
|
reflection.options[:through] ? HasManyThrough : HasMany
|
169
185
|
when :has_one
|
170
186
|
reflection.options[:through] ? HasOneThrough : HasOne
|
171
|
-
when :has_and_belongs_to_many
|
172
|
-
HasAndBelongsToMany
|
173
187
|
when :belongs_to
|
174
188
|
BelongsTo
|
175
189
|
end
|
@@ -18,11 +18,11 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def create(attributes = {}, &block)
|
21
|
-
|
21
|
+
_create_record(attributes, &block)
|
22
22
|
end
|
23
23
|
|
24
24
|
def create!(attributes = {}, &block)
|
25
|
-
|
25
|
+
_create_record(attributes, true, &block)
|
26
26
|
end
|
27
27
|
|
28
28
|
def build(attributes = {})
|
@@ -39,10 +39,11 @@ module ActiveRecord
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def find_target
|
42
|
-
|
42
|
+
if record = scope.take
|
43
|
+
set_inverse_instance record
|
44
|
+
end
|
43
45
|
end
|
44
46
|
|
45
|
-
# Implemented by subclasses
|
46
47
|
def replace(record)
|
47
48
|
raise NotImplementedError, "Subclasses must implement a replace(record) method"
|
48
49
|
end
|
@@ -51,7 +52,7 @@ module ActiveRecord
|
|
51
52
|
replace(record)
|
52
53
|
end
|
53
54
|
|
54
|
-
def
|
55
|
+
def _create_record(attributes, raise_error = false)
|
55
56
|
record = build_record(attributes)
|
56
57
|
yield(record) if block_given?
|
57
58
|
saved = record.save
|
@@ -13,10 +13,16 @@ module ActiveRecord
|
|
13
13
|
# 2. To get the type conditions for any STI models in the chain
|
14
14
|
def target_scope
|
15
15
|
scope = super
|
16
|
-
chain
|
16
|
+
chain.drop(1).each do |reflection|
|
17
|
+
relation = reflection.klass.all
|
18
|
+
|
19
|
+
reflection_scope = reflection.scope
|
20
|
+
if reflection_scope && reflection_scope.arity.zero?
|
21
|
+
relation.merge!(reflection_scope)
|
22
|
+
end
|
23
|
+
|
17
24
|
scope.merge!(
|
18
|
-
|
19
|
-
except(:select, :create_with, :includes, :preload, :joins, :eager_load)
|
25
|
+
relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
|
20
26
|
)
|
21
27
|
end
|
22
28
|
scope
|
@@ -39,12 +45,16 @@ module ActiveRecord
|
|
39
45
|
def construct_join_attributes(*records)
|
40
46
|
ensure_mutable
|
41
47
|
|
42
|
-
|
43
|
-
source_reflection.
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
+
if source_reflection.association_primary_key(reflection.klass) == reflection.klass.primary_key
|
49
|
+
join_attributes = { source_reflection.name => records }
|
50
|
+
else
|
51
|
+
join_attributes = {
|
52
|
+
source_reflection.foreign_key =>
|
53
|
+
records.map { |record|
|
54
|
+
record.send(source_reflection.association_primary_key(reflection.klass))
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
48
58
|
|
49
59
|
if options[:source_type]
|
50
60
|
join_attributes[source_reflection.foreign_type] =
|
@@ -82,6 +92,17 @@ module ActiveRecord
|
|
82
92
|
raise HasManyThroughNestedAssociationsAreReadonly.new(owner, reflection)
|
83
93
|
end
|
84
94
|
end
|
95
|
+
|
96
|
+
def build_record(attributes)
|
97
|
+
inverse = source_reflection.inverse_of
|
98
|
+
target = through_association.target
|
99
|
+
|
100
|
+
if inverse && target && !target.is_a?(Array)
|
101
|
+
attributes[inverse.foreign_key] = target.id
|
102
|
+
end
|
103
|
+
|
104
|
+
super(attributes)
|
105
|
+
end
|
85
106
|
end
|
86
107
|
end
|
87
108
|
end
|