activerecord 5.2.6 → 6.0.0.beta1
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 +299 -758
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/associations/association.rb +35 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/belongs_to.rb +14 -50
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/collection_association.rb +11 -25
- data/lib/active_record/associations/collection_proxy.rb +32 -6
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +25 -18
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +34 -56
- data/lib/active_record/attribute_methods/dirty.rb +64 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -7
- data/lib/active_record/attribute_methods/read.rb +16 -48
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +15 -16
- data/lib/active_record/autosave_association.rb +7 -21
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +3 -17
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
- data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
- data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
- data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
- data/lib/active_record/connection_handling.rb +132 -26
- data/lib/active_record/core.rb +76 -43
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +184 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +74 -0
- data/lib/active_record/enum.rb +22 -7
- data/lib/active_record/errors.rb +24 -21
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +12 -2
- data/lib/active_record/integration.rb +56 -16
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/migration.rb +38 -37
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +18 -7
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +19 -11
- data/lib/active_record/railtie.rb +71 -42
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +94 -43
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation.rb +150 -69
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +38 -28
- data/lib/active_record/relation/delegation.rb +4 -13
- data/lib/active_record/relation/finder_methods.rb +12 -25
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +15 -12
- data/lib/active_record/relation/query_methods.rb +29 -52
- data/lib/active_record/relation/where_clause.rb +4 -0
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +2 -39
- data/lib/active_record/schema.rb +1 -10
- data/lib/active_record/schema_dumper.rb +12 -6
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +39 -8
- data/lib/active_record/table_metadata.rb +1 -4
- data/lib/active_record/tasks/database_tasks.rb +89 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +38 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/transactions.rb +3 -22
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +1 -6
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +13 -25
- data/lib/arel.rb +44 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +67 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +63 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values.rb +16 -0
- data/lib/arel/nodes/values_list.rb +24 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +199 -0
- data/lib/arel/visitors/dot.rb +292 -0
- data/lib/arel/visitors/ibm_db.rb +21 -0
- data/lib/arel/visitors/informix.rb +56 -0
- data/lib/arel/visitors/mssql.rb +143 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +67 -0
- data/lib/arel/visitors/postgresql.rb +116 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +913 -0
- data/lib/arel/visitors/visitor.rb +42 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +104 -26
@@ -20,11 +20,11 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.define_extensions(model, name
|
23
|
+
def self.define_extensions(model, name)
|
24
24
|
if block_given?
|
25
25
|
extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
|
26
|
-
extension = Module.new(&
|
27
|
-
model.
|
26
|
+
extension = Module.new(&Proc.new)
|
27
|
+
model.module_parent.const_set(extension_module_name, extension)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -2,39 +2,6 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord::Associations::Builder # :nodoc:
|
4
4
|
class HasAndBelongsToMany # :nodoc:
|
5
|
-
class JoinTableResolver # :nodoc:
|
6
|
-
KnownTable = Struct.new :join_table
|
7
|
-
|
8
|
-
class KnownClass # :nodoc:
|
9
|
-
def initialize(lhs_class, rhs_class_name)
|
10
|
-
@lhs_class = lhs_class
|
11
|
-
@rhs_class_name = rhs_class_name
|
12
|
-
@join_table = nil
|
13
|
-
end
|
14
|
-
|
15
|
-
def join_table
|
16
|
-
@join_table ||= [@lhs_class.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def klass
|
22
|
-
@lhs_class.send(:compute_type, @rhs_class_name)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.build(lhs_class, name, options)
|
27
|
-
if options[:join_table]
|
28
|
-
KnownTable.new options[:join_table].to_s
|
29
|
-
else
|
30
|
-
class_name = options.fetch(:class_name) {
|
31
|
-
name.to_s.camelize.singularize
|
32
|
-
}
|
33
|
-
KnownClass.new lhs_class, class_name.to_s
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
5
|
attr_reader :lhs_model, :association_name, :options
|
39
6
|
|
40
7
|
def initialize(association_name, lhs_model, options)
|
@@ -44,8 +11,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
44
11
|
end
|
45
12
|
|
46
13
|
def through_model
|
47
|
-
habtm = JoinTableResolver.build lhs_model, association_name, options
|
48
|
-
|
49
14
|
join_model = Class.new(ActiveRecord::Base) {
|
50
15
|
class << self
|
51
16
|
attr_accessor :left_model
|
@@ -56,7 +21,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
56
21
|
end
|
57
22
|
|
58
23
|
def self.table_name
|
59
|
-
|
24
|
+
# Table name needs to be resolved lazily
|
25
|
+
# because RHS class might not have been loaded
|
26
|
+
@table_name ||= table_name_resolver.call
|
60
27
|
end
|
61
28
|
|
62
29
|
def self.compute_type(class_name)
|
@@ -86,7 +53,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
86
53
|
}
|
87
54
|
|
88
55
|
join_model.name = "HABTM_#{association_name.to_s.camelize}"
|
89
|
-
join_model.table_name_resolver =
|
56
|
+
join_model.table_name_resolver = -> { table_name }
|
90
57
|
join_model.left_model = lhs_model
|
91
58
|
|
92
59
|
join_model.add_left_association :left_side, anonymous_class: lhs_model
|
@@ -96,7 +63,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
96
63
|
|
97
64
|
def middle_reflection(join_model)
|
98
65
|
middle_name = [lhs_model.name.downcase.pluralize,
|
99
|
-
association_name].join("_"
|
66
|
+
association_name].join("_").gsub("::", "_").to_sym
|
100
67
|
middle_options = middle_options join_model
|
101
68
|
|
102
69
|
HasMany.create_reflection(lhs_model,
|
@@ -117,6 +84,18 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
117
84
|
middle_options
|
118
85
|
end
|
119
86
|
|
87
|
+
def table_name
|
88
|
+
if options[:join_table]
|
89
|
+
options[:join_table].to_s
|
90
|
+
else
|
91
|
+
class_name = options.fetch(:class_name) {
|
92
|
+
association_name.to_s.camelize.singularize
|
93
|
+
}
|
94
|
+
klass = lhs_model.send(:compute_type, class_name.to_s)
|
95
|
+
[lhs_model.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
120
99
|
def belongs_to_options(options)
|
121
100
|
rhs_options = {}
|
122
101
|
|
@@ -109,8 +109,9 @@ module ActiveRecord
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
-
# Add +records+ to this association.
|
113
|
-
#
|
112
|
+
# Add +records+ to this association. Returns +self+ so method calls may
|
113
|
+
# be chained. Since << flattens its argument list and inserts each record,
|
114
|
+
# +push+ and +concat+ behave identically.
|
114
115
|
def concat(*records)
|
115
116
|
records = records.flatten
|
116
117
|
if owner.new_record?
|
@@ -211,9 +212,11 @@ module ActiveRecord
|
|
211
212
|
def size
|
212
213
|
if !find_target? || loaded?
|
213
214
|
target.size
|
215
|
+
elsif @association_ids
|
216
|
+
@association_ids.size
|
214
217
|
elsif !association_scope.group_values.empty?
|
215
218
|
load_target.size
|
216
|
-
elsif !association_scope.distinct_value && target.
|
219
|
+
elsif !association_scope.distinct_value && !target.empty?
|
217
220
|
unsaved_records = target.select(&:new_record?)
|
218
221
|
unsaved_records.size + count_records
|
219
222
|
else
|
@@ -230,10 +233,10 @@ module ActiveRecord
|
|
230
233
|
# loaded and you are going to fetch the records anyway it is better to
|
231
234
|
# check <tt>collection.length.zero?</tt>.
|
232
235
|
def empty?
|
233
|
-
if loaded?
|
236
|
+
if loaded? || @association_ids
|
234
237
|
size.zero?
|
235
238
|
else
|
236
|
-
|
239
|
+
target.empty? && !scope.exists?
|
237
240
|
end
|
238
241
|
end
|
239
242
|
|
@@ -300,23 +303,6 @@ module ActiveRecord
|
|
300
303
|
end
|
301
304
|
|
302
305
|
private
|
303
|
-
|
304
|
-
def find_target
|
305
|
-
scope = self.scope
|
306
|
-
return scope.to_a if skip_statement_cache?(scope)
|
307
|
-
|
308
|
-
conn = klass.connection
|
309
|
-
sc = reflection.association_scope_cache(conn, owner) do |params|
|
310
|
-
as = AssociationScope.create { params.bind }
|
311
|
-
target_scope.merge!(as.scope(self))
|
312
|
-
end
|
313
|
-
|
314
|
-
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
315
|
-
sc.execute(binds, conn) do |record|
|
316
|
-
set_inverse_instance(record)
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
306
|
# We have some records loaded from the database (persisted) and some that are
|
321
307
|
# in-memory (memory). The same record may be represented in the persisted array
|
322
308
|
# and in the memory array.
|
@@ -361,6 +347,7 @@ module ActiveRecord
|
|
361
347
|
add_to_target(record) do
|
362
348
|
result = insert_record(record, true, raise) {
|
363
349
|
@_was_loaded = loaded?
|
350
|
+
@association_ids = nil
|
364
351
|
}
|
365
352
|
end
|
366
353
|
raise ActiveRecord::Rollback unless result
|
@@ -396,8 +383,7 @@ module ActiveRecord
|
|
396
383
|
records.each { |record| callback(:before_remove, record) }
|
397
384
|
|
398
385
|
delete_records(existing_records, method) if existing_records.any?
|
399
|
-
|
400
|
-
@association_ids = nil
|
386
|
+
@target -= records
|
401
387
|
|
402
388
|
records.each { |record| callback(:after_remove, record) }
|
403
389
|
end
|
@@ -438,6 +424,7 @@ module ActiveRecord
|
|
438
424
|
unless owner.new_record?
|
439
425
|
result &&= insert_record(record, true, raise) {
|
440
426
|
@_was_loaded = loaded?
|
427
|
+
@association_ids = nil
|
441
428
|
}
|
442
429
|
end
|
443
430
|
end
|
@@ -460,7 +447,6 @@ module ActiveRecord
|
|
460
447
|
if index
|
461
448
|
target[index] = record
|
462
449
|
elsif @_was_loaded || !loaded?
|
463
|
-
@association_ids = nil
|
464
450
|
target << record
|
465
451
|
end
|
466
452
|
|
@@ -366,6 +366,34 @@ module ActiveRecord
|
|
366
366
|
@association.create!(attributes, &block)
|
367
367
|
end
|
368
368
|
|
369
|
+
# Add one or more records to the collection by setting their foreign keys
|
370
|
+
# to the association's primary key. Since #<< flattens its argument list and
|
371
|
+
# inserts each record, +push+ and #concat behave identically. Returns +self+
|
372
|
+
# so method calls may be chained.
|
373
|
+
#
|
374
|
+
# class Person < ActiveRecord::Base
|
375
|
+
# has_many :pets
|
376
|
+
# end
|
377
|
+
#
|
378
|
+
# person.pets.size # => 0
|
379
|
+
# person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
|
380
|
+
# person.pets.concat(Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo'))
|
381
|
+
# person.pets.size # => 3
|
382
|
+
#
|
383
|
+
# person.id # => 1
|
384
|
+
# person.pets
|
385
|
+
# # => [
|
386
|
+
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
|
387
|
+
# # #<Pet id: 2, name: "Spook", person_id: 1>,
|
388
|
+
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
|
389
|
+
# # ]
|
390
|
+
#
|
391
|
+
# person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
|
392
|
+
# person.pets.size # => 5
|
393
|
+
def concat(*records)
|
394
|
+
@association.concat(*records)
|
395
|
+
end
|
396
|
+
|
369
397
|
# Replaces this collection with +other_array+. This will perform a diff
|
370
398
|
# and delete/add only records that have changed.
|
371
399
|
#
|
@@ -1005,9 +1033,8 @@ module ActiveRecord
|
|
1005
1033
|
end
|
1006
1034
|
|
1007
1035
|
# Adds one or more +records+ to the collection by setting their foreign keys
|
1008
|
-
# to the association's primary key.
|
1009
|
-
#
|
1010
|
-
# so several appends may be chained together.
|
1036
|
+
# to the association's primary key. Returns +self+, so several appends may be
|
1037
|
+
# chained together.
|
1011
1038
|
#
|
1012
1039
|
# class Person < ActiveRecord::Base
|
1013
1040
|
# has_many :pets
|
@@ -1030,7 +1057,6 @@ module ActiveRecord
|
|
1030
1057
|
end
|
1031
1058
|
alias_method :push, :<<
|
1032
1059
|
alias_method :append, :<<
|
1033
|
-
alias_method :concat, :<<
|
1034
1060
|
|
1035
1061
|
def prepend(*args)
|
1036
1062
|
raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
|
@@ -1062,7 +1088,7 @@ module ActiveRecord
|
|
1062
1088
|
# person.pets.reload # fetches pets from the database
|
1063
1089
|
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
|
1064
1090
|
def reload
|
1065
|
-
proxy_association.reload
|
1091
|
+
proxy_association.reload(true)
|
1066
1092
|
reset_scope
|
1067
1093
|
end
|
1068
1094
|
|
@@ -1099,7 +1125,7 @@ module ActiveRecord
|
|
1099
1125
|
SpawnMethods,
|
1100
1126
|
].flat_map { |klass|
|
1101
1127
|
klass.public_instance_methods(false)
|
1102
|
-
} - self.public_instance_methods(false) - [:select] + [:scoping]
|
1128
|
+
} - self.public_instance_methods(false) - [:select] + [:scoping, :values]
|
1103
1129
|
|
1104
1130
|
delegate(*delegate_methods, to: :scope)
|
1105
1131
|
|
@@ -21,20 +21,6 @@ module ActiveRecord
|
|
21
21
|
super
|
22
22
|
end
|
23
23
|
|
24
|
-
def concat_records(records)
|
25
|
-
ensure_not_nested
|
26
|
-
|
27
|
-
records = super(records, true)
|
28
|
-
|
29
|
-
if owner.new_record? && records
|
30
|
-
records.flatten.each do |record|
|
31
|
-
build_through_record(record)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
records
|
36
|
-
end
|
37
|
-
|
38
24
|
def insert_record(record, validate = true, raise = false)
|
39
25
|
ensure_not_nested
|
40
26
|
|
@@ -48,6 +34,20 @@ module ActiveRecord
|
|
48
34
|
end
|
49
35
|
|
50
36
|
private
|
37
|
+
def concat_records(records)
|
38
|
+
ensure_not_nested
|
39
|
+
|
40
|
+
records = super(records, true)
|
41
|
+
|
42
|
+
if owner.new_record? && records
|
43
|
+
records.flatten.each do |record|
|
44
|
+
build_through_record(record)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
records
|
49
|
+
end
|
50
|
+
|
51
51
|
# The through record (built with build_record) is temporarily cached
|
52
52
|
# so that it may be reused if insert_record is subsequently called.
|
53
53
|
#
|
@@ -57,14 +57,21 @@ module ActiveRecord
|
|
57
57
|
@through_records[record.object_id] ||= begin
|
58
58
|
ensure_mutable
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
through_record = through_association.build(*options_for_through_record)
|
61
|
+
through_record.send("#{source_reflection.name}=", record)
|
62
|
+
|
63
|
+
if options[:source_type]
|
64
|
+
through_record.send("#{source_reflection.foreign_type}=", options[:source_type])
|
65
|
+
end
|
63
66
|
|
64
|
-
|
67
|
+
through_record
|
65
68
|
end
|
66
69
|
end
|
67
70
|
|
71
|
+
def options_for_through_record
|
72
|
+
[through_scope_attributes]
|
73
|
+
end
|
74
|
+
|
68
75
|
def through_scope_attributes
|
69
76
|
scope.where_values_hash(through_association.reflection.name.to_s).
|
70
77
|
except!(through_association.reflection.foreign_key,
|
@@ -23,35 +23,6 @@ module ActiveRecord
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def replace(record, save = true)
|
27
|
-
raise_on_type_mismatch!(record) if record
|
28
|
-
load_target
|
29
|
-
|
30
|
-
return target unless target || record
|
31
|
-
|
32
|
-
assigning_another_record = target != record
|
33
|
-
if assigning_another_record || record.has_changes_to_save?
|
34
|
-
save &&= owner.persisted?
|
35
|
-
|
36
|
-
transaction_if(save) do
|
37
|
-
remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
|
38
|
-
|
39
|
-
if record
|
40
|
-
set_owner_attributes(record)
|
41
|
-
set_inverse_instance(record)
|
42
|
-
|
43
|
-
if save && !record.save
|
44
|
-
nullify_owner_attributes(record)
|
45
|
-
set_owner_attributes(target) if target
|
46
|
-
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
self.target = record
|
53
|
-
end
|
54
|
-
|
55
26
|
def delete(method = options[:dependent])
|
56
27
|
if load_target
|
57
28
|
case method
|
@@ -62,12 +33,39 @@ module ActiveRecord
|
|
62
33
|
target.destroy
|
63
34
|
throw(:abort) unless target.destroyed?
|
64
35
|
when :nullify
|
65
|
-
target.update_columns(
|
36
|
+
target.update_columns(nullified_owner_attributes) if target.persisted?
|
66
37
|
end
|
67
38
|
end
|
68
39
|
end
|
69
40
|
|
70
41
|
private
|
42
|
+
def replace(record, save = true)
|
43
|
+
raise_on_type_mismatch!(record) if record
|
44
|
+
|
45
|
+
return target unless load_target || record
|
46
|
+
|
47
|
+
assigning_another_record = target != record
|
48
|
+
if assigning_another_record || record.has_changes_to_save?
|
49
|
+
save &&= owner.persisted?
|
50
|
+
|
51
|
+
transaction_if(save) do
|
52
|
+
remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
|
53
|
+
|
54
|
+
if record
|
55
|
+
set_owner_attributes(record)
|
56
|
+
set_inverse_instance(record)
|
57
|
+
|
58
|
+
if save && !record.save
|
59
|
+
nullify_owner_attributes(record)
|
60
|
+
set_owner_attributes(target) if target
|
61
|
+
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
self.target = record
|
68
|
+
end
|
71
69
|
|
72
70
|
# The reason that the save param for replace is false, if for create (not just build),
|
73
71
|
# is because the setting of the foreign keys is actually handled by the scoping when
|
@@ -6,12 +6,12 @@ module ActiveRecord
|
|
6
6
|
class HasOneThroughAssociation < HasOneAssociation #:nodoc:
|
7
7
|
include ThroughAssociation
|
8
8
|
|
9
|
-
def replace(record, save = true)
|
10
|
-
create_through_record(record, save)
|
11
|
-
self.target = record
|
12
|
-
end
|
13
|
-
|
14
9
|
private
|
10
|
+
def replace(record, save = true)
|
11
|
+
create_through_record(record, save)
|
12
|
+
self.target = record
|
13
|
+
end
|
14
|
+
|
15
15
|
def create_through_record(record, save)
|
16
16
|
ensure_not_nested
|
17
17
|
|