activerecord 7.1.4.1 → 7.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +643 -2274
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +14 -7
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +7 -1
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +4 -4
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +59 -292
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods.rb +54 -63
- data/lib/active_record/attributes.rb +61 -47
- data/lib/active_record/autosave_association.rb +12 -29
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +270 -65
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +189 -74
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +40 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +6 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +16 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +17 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +29 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -75
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +86 -38
- data/lib/active_record/counter_cache.rb +18 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +24 -0
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +3 -3
- data/lib/active_record/encryption/encrypted_attribute_type.rb +24 -4
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +19 -2
- data/lib/active_record/errors.rb +46 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +85 -76
- data/lib/active_record/model_schema.rb +32 -68
- data/lib/active_record/nested_attributes.rb +24 -5
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +42 -57
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +40 -43
- data/lib/active_record/reflection.rb +98 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +96 -63
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -3
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +224 -58
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +496 -72
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/signed_id.rb +20 -1
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +81 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +86 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +70 -14
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +15 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +148 -39
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -12
data/README.rdoc
CHANGED
@@ -34,7 +34,7 @@ A short rundown of some of the major features:
|
|
34
34
|
This would also define the following accessors: <tt>Product#name</tt> and
|
35
35
|
<tt>Product#name=(new_name)</tt>.
|
36
36
|
|
37
|
-
{Learn more}[
|
37
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Base.html]
|
38
38
|
|
39
39
|
* Associations between objects defined by simple class methods.
|
40
40
|
|
@@ -44,7 +44,7 @@ A short rundown of some of the major features:
|
|
44
44
|
belongs_to :conglomerate
|
45
45
|
end
|
46
46
|
|
47
|
-
{Learn more}[
|
47
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html]
|
48
48
|
|
49
49
|
|
50
50
|
* Aggregations of value objects.
|
@@ -56,7 +56,7 @@ A short rundown of some of the major features:
|
|
56
56
|
mapping: [%w(address_street street), %w(address_city city)]
|
57
57
|
end
|
58
58
|
|
59
|
-
{Learn more}[
|
59
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html]
|
60
60
|
|
61
61
|
|
62
62
|
* Validation rules that can differ for new or existing objects.
|
@@ -68,7 +68,7 @@ A short rundown of some of the major features:
|
|
68
68
|
validates :password, :email_address, confirmation: true, on: :create
|
69
69
|
end
|
70
70
|
|
71
|
-
{Learn more}[
|
71
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Validations.html]
|
72
72
|
|
73
73
|
|
74
74
|
* Callbacks available for the entire life cycle (instantiation, saving, destroying, validating, etc.).
|
@@ -78,7 +78,7 @@ A short rundown of some of the major features:
|
|
78
78
|
# the `invalidate_payment_plan` method gets called just before Person#destroy
|
79
79
|
end
|
80
80
|
|
81
|
-
{Learn more}[
|
81
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html]
|
82
82
|
|
83
83
|
|
84
84
|
* Inheritance hierarchies.
|
@@ -88,7 +88,7 @@ A short rundown of some of the major features:
|
|
88
88
|
class Client < Company; end
|
89
89
|
class PriorityClient < Client; end
|
90
90
|
|
91
|
-
{Learn more}[
|
91
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Base.html]
|
92
92
|
|
93
93
|
|
94
94
|
* Transactions.
|
@@ -99,7 +99,7 @@ A short rundown of some of the major features:
|
|
99
99
|
mary.deposit(100)
|
100
100
|
end
|
101
101
|
|
102
|
-
{Learn more}[
|
102
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html]
|
103
103
|
|
104
104
|
|
105
105
|
* Reflections on columns, associations, and aggregations.
|
@@ -108,7 +108,7 @@ A short rundown of some of the major features:
|
|
108
108
|
reflection.klass # => Client (class)
|
109
109
|
Firm.columns # Returns an array of column descriptors for the firms table
|
110
110
|
|
111
|
-
{Learn more}[
|
111
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html]
|
112
112
|
|
113
113
|
|
114
114
|
* Database abstraction through simple adapters.
|
@@ -125,13 +125,13 @@ A short rundown of some of the major features:
|
|
125
125
|
database: 'activerecord'
|
126
126
|
)
|
127
127
|
|
128
|
-
{Learn more}[
|
129
|
-
MySQL[
|
130
|
-
PostgreSQL[
|
131
|
-
SQLite3[
|
128
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Base.html] and read about the built-in support for
|
129
|
+
MySQL[https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html],
|
130
|
+
PostgreSQL[https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html], and
|
131
|
+
SQLite3[https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
|
132
132
|
|
133
133
|
|
134
|
-
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://ruby-
|
134
|
+
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://docs.ruby-lang.org/en/master/Logger.html].
|
135
135
|
|
136
136
|
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
137
137
|
ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
|
@@ -139,7 +139,7 @@ A short rundown of some of the major features:
|
|
139
139
|
|
140
140
|
* Database agnostic schema management with Migrations.
|
141
141
|
|
142
|
-
class AddSystemSettings < ActiveRecord::Migration[7.
|
142
|
+
class AddSystemSettings < ActiveRecord::Migration[7.2]
|
143
143
|
def up
|
144
144
|
create_table :system_settings do |t|
|
145
145
|
t.string :name
|
@@ -157,7 +157,7 @@ A short rundown of some of the major features:
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
-
{Learn more}[
|
160
|
+
{Learn more}[https://api.rubyonrails.org/classes/ActiveRecord/Migration.html]
|
161
161
|
|
162
162
|
|
163
163
|
== Philosophy
|
data/examples/performance.rb
CHANGED
@@ -176,10 +176,10 @@ Benchmark.ips(TIME) do |x|
|
|
176
176
|
end
|
177
177
|
|
178
178
|
x.report "Model.log" do
|
179
|
-
Exhibit.
|
179
|
+
Exhibit.lease_connection.send(:log, "hello", "world") { }
|
180
180
|
end
|
181
181
|
|
182
182
|
x.report "AR.execute(query)" do
|
183
|
-
ActiveRecord::Base.
|
183
|
+
ActiveRecord::Base.lease_connection.execute("SELECT * FROM exhibits WHERE id = #{(rand * 1000 + 1).to_i}")
|
184
184
|
end
|
185
185
|
end
|
@@ -6,21 +6,23 @@ module ActiveRecord
|
|
6
6
|
module Associations
|
7
7
|
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
8
8
|
class AliasTracker # :nodoc:
|
9
|
-
def self.create(
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
def self.create(pool, initial_table, joins, aliases = nil)
|
10
|
+
pool.with_connection do |connection|
|
11
|
+
if joins.empty?
|
12
|
+
aliases ||= Hash.new(0)
|
13
|
+
elsif aliases
|
14
|
+
default_proc = aliases.default_proc || proc { 0 }
|
15
|
+
aliases.default_proc = proc { |h, k|
|
16
|
+
h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
|
17
|
+
}
|
18
|
+
else
|
19
|
+
aliases = Hash.new { |h, k|
|
20
|
+
h[k] = initial_count_for(connection, k, joins)
|
21
|
+
}
|
22
|
+
end
|
23
|
+
aliases[initial_table] = 1
|
24
|
+
new(connection.table_alias_length, aliases)
|
21
25
|
end
|
22
|
-
aliases[initial_table] = 1
|
23
|
-
new(connection, aliases)
|
24
26
|
end
|
25
27
|
|
26
28
|
def self.initial_count_for(connection, name, table_joins)
|
@@ -46,9 +48,9 @@ module ActiveRecord
|
|
46
48
|
end
|
47
49
|
|
48
50
|
# table_joins is an array of arel joins which might conflict with the aliases we assign here
|
49
|
-
def initialize(
|
50
|
-
@aliases
|
51
|
-
@
|
51
|
+
def initialize(table_alias_length, aliases)
|
52
|
+
@aliases = aliases
|
53
|
+
@table_alias_length = table_alias_length
|
52
54
|
end
|
53
55
|
|
54
56
|
def aliased_table_for(arel_table, table_name = nil)
|
@@ -60,7 +62,7 @@ module ActiveRecord
|
|
60
62
|
arel_table = arel_table.alias(table_name) if arel_table.name != table_name
|
61
63
|
else
|
62
64
|
# Otherwise, we need to use an alias
|
63
|
-
aliased_name =
|
65
|
+
aliased_name = table_alias_for(yield)
|
64
66
|
|
65
67
|
# Update the count
|
66
68
|
count = aliases[aliased_name] += 1
|
@@ -76,8 +78,12 @@ module ActiveRecord
|
|
76
78
|
attr_reader :aliases
|
77
79
|
|
78
80
|
private
|
81
|
+
def table_alias_for(table_name)
|
82
|
+
table_name[0...@table_alias_length].tr(".", "_")
|
83
|
+
end
|
84
|
+
|
79
85
|
def truncate(name)
|
80
|
-
name.slice(0, @
|
86
|
+
name.slice(0, @table_alias_length - 2)
|
81
87
|
end
|
82
88
|
end
|
83
89
|
end
|
@@ -53,7 +53,6 @@ module ActiveRecord
|
|
53
53
|
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
|
54
54
|
def reset
|
55
55
|
@loaded = false
|
56
|
-
@target = nil
|
57
56
|
@stale_state = nil
|
58
57
|
end
|
59
58
|
|
@@ -64,7 +63,7 @@ module ActiveRecord
|
|
64
63
|
# Reloads the \target and returns +self+ on success.
|
65
64
|
# The QueryCache is cleared if +force+ is true.
|
66
65
|
def reload(force = false)
|
67
|
-
klass.
|
66
|
+
klass.connection_pool.clear_query_cache if force && klass
|
68
67
|
reset
|
69
68
|
reset_scope
|
70
69
|
load_target
|
@@ -211,6 +210,12 @@ module ActiveRecord
|
|
211
210
|
_create_record(attributes, true, &block)
|
212
211
|
end
|
213
212
|
|
213
|
+
# Whether the association represent a single record
|
214
|
+
# or a collection of records.
|
215
|
+
def collection?
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
214
219
|
private
|
215
220
|
# Reader and writer methods call this so that consistent errors are presented
|
216
221
|
# when the association target class does not exist.
|
@@ -232,12 +237,14 @@ module ActiveRecord
|
|
232
237
|
end
|
233
238
|
|
234
239
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
240
|
+
klass.with_connection do |c|
|
241
|
+
sc.execute(binds, c) do |record|
|
242
|
+
set_inverse_instance(record)
|
243
|
+
if owner.strict_loading_n_plus_one_only? && reflection.macro == :has_many
|
244
|
+
record.strict_loading!
|
245
|
+
else
|
246
|
+
record.strict_loading!(false, mode: owner.strict_loading_mode)
|
247
|
+
end
|
241
248
|
end
|
242
249
|
end
|
243
250
|
end
|
@@ -124,12 +124,20 @@ module ActiveRecord
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def replace_keys(record, force: false)
|
127
|
-
|
128
|
-
reflection_fk
|
127
|
+
reflection_fk = reflection.foreign_key
|
128
|
+
if reflection_fk.is_a?(Array)
|
129
|
+
target_key_values = record ? Array(primary_key(record.class)).map { |key| record._read_attribute(key) } : []
|
130
|
+
|
131
|
+
if force || reflection_fk.map { |fk| owner._read_attribute(fk) } != target_key_values
|
132
|
+
reflection_fk.each_with_index do |key, index|
|
133
|
+
owner[key] = target_key_values[index]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
else
|
137
|
+
target_key_value = record ? record._read_attribute(primary_key(record.class)) : nil
|
129
138
|
|
130
|
-
|
131
|
-
|
132
|
-
owner[key] = value
|
139
|
+
if force || owner._read_attribute(reflection_fk) != target_key_value
|
140
|
+
owner[reflection_fk] = target_key_value
|
133
141
|
end
|
134
142
|
end
|
135
143
|
end
|
@@ -148,8 +156,7 @@ module ActiveRecord
|
|
148
156
|
end
|
149
157
|
|
150
158
|
def stale_state
|
151
|
-
|
152
|
-
result && result.to_s
|
159
|
+
owner._read_attribute(reflection.foreign_key) { |n| owner.send(:missing_attribute, n, caller) }
|
153
160
|
end
|
154
161
|
end
|
155
162
|
end
|
@@ -38,6 +38,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
38
38
|
|
39
39
|
klass = reflection.class_name.safe_constantize
|
40
40
|
klass._counter_cache_columns |= [cache_column] if klass && klass.respond_to?(:_counter_cache_columns)
|
41
|
+
model.counter_cached_association_names |= [reflection.name]
|
41
42
|
end
|
42
43
|
|
43
44
|
def self.touch_record(o, changes, foreign_key, name, touch) # :nodoc:
|
@@ -42,8 +42,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
42
42
|
self.right_reflection = _reflect_on_association(rhs_name)
|
43
43
|
end
|
44
44
|
|
45
|
-
def self.
|
46
|
-
left_model.
|
45
|
+
def self.connection_pool
|
46
|
+
left_model.connection_pool
|
47
47
|
end
|
48
48
|
}
|
49
49
|
|
@@ -7,11 +7,10 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
valid = super + [:counter_cache, :join_table, :index_errors]
|
11
|
-
valid += [:
|
12
|
-
valid += [:
|
10
|
+
valid = super + [:counter_cache, :join_table, :index_errors, :as, :through]
|
11
|
+
valid += [:foreign_type] if options[:as]
|
12
|
+
valid += [:source, :source_type, :disable_joins] if options[:through]
|
13
13
|
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
14
|
-
valid += [:disable_joins] if options[:disable_joins] && options[:through]
|
15
14
|
valid
|
16
15
|
end
|
17
16
|
|
@@ -7,11 +7,10 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
valid = super
|
11
|
-
valid += [:
|
10
|
+
valid = super + [:as, :through]
|
11
|
+
valid += [:foreign_type] if options[:as]
|
12
12
|
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
13
|
-
valid += [:
|
14
|
-
valid += [:disable_joins] if options[:disable_joins] && options[:through]
|
13
|
+
valid += [:source, :source_type, :disable_joins] if options[:through]
|
15
14
|
valid
|
16
15
|
end
|
17
16
|
|
@@ -28,6 +28,8 @@ module ActiveRecord
|
|
28
28
|
# If you need to work on all current children, new and existing records,
|
29
29
|
# +load_target+ and the +loaded+ flag are your friends.
|
30
30
|
class CollectionAssociation < Association # :nodoc:
|
31
|
+
attr_accessor :nested_attributes_target
|
32
|
+
|
31
33
|
# Implements the reader method, e.g. foo.items for Foo.has_many :items
|
32
34
|
def reader
|
33
35
|
ensure_klass_exists!
|
@@ -228,7 +230,7 @@ module ActiveRecord
|
|
228
230
|
# loaded and you are going to fetch the records anyway it is better to
|
229
231
|
# check <tt>collection.length.zero?</tt>.
|
230
232
|
def empty?
|
231
|
-
if loaded? || @association_ids || reflection.
|
233
|
+
if loaded? || @association_ids || reflection.has_active_cached_counter?
|
232
234
|
size.zero?
|
233
235
|
else
|
234
236
|
target.empty? && !scope.exists?
|
@@ -309,6 +311,10 @@ module ActiveRecord
|
|
309
311
|
target.any? { |record| record.new_record? || record.changed? }
|
310
312
|
end
|
311
313
|
|
314
|
+
def collection?
|
315
|
+
true
|
316
|
+
end
|
317
|
+
|
312
318
|
private
|
313
319
|
def transaction(&block)
|
314
320
|
reflection.klass.transaction(&block)
|
@@ -928,7 +928,20 @@ module ActiveRecord
|
|
928
928
|
!!@association.include?(record)
|
929
929
|
end
|
930
930
|
|
931
|
-
|
931
|
+
# Returns the association object for the collection.
|
932
|
+
#
|
933
|
+
# class Person < ActiveRecord::Base
|
934
|
+
# has_many :pets
|
935
|
+
# end
|
936
|
+
#
|
937
|
+
# person.pets.proxy_association
|
938
|
+
# # => #<ActiveRecord::Associations::HasManyAssociation owner="#<Person:0x00>">
|
939
|
+
#
|
940
|
+
# Returns the same object as <tt>person.association(:pets)</tt>,
|
941
|
+
# allowing you to make calls like <tt>person.pets.proxy_association.owner</tt>.
|
942
|
+
#
|
943
|
+
# See Associations::ClassMethods@Association+extensions for more.
|
944
|
+
def proxy_association
|
932
945
|
@association
|
933
946
|
end
|
934
947
|
|