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
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
9
9
|
|
10
10
|
def handle_dependency
|
11
11
|
case options[:dependent]
|
12
|
-
when :
|
12
|
+
when :restrict_with_exception
|
13
13
|
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
|
14
14
|
|
15
15
|
when :restrict_with_error
|
@@ -59,8 +59,6 @@ module ActiveRecord
|
|
59
59
|
def count_records
|
60
60
|
count = if has_cached_counter?
|
61
61
|
owner.send(:read_attribute, cached_counter_attribute_name)
|
62
|
-
elsif options[:counter_sql] || options[:finder_sql]
|
63
|
-
reflection.klass.count_by_sql(custom_counter_sql)
|
64
62
|
else
|
65
63
|
scope.count
|
66
64
|
end
|
@@ -73,15 +71,15 @@ module ActiveRecord
|
|
73
71
|
[association_scope.limit_value, count].compact.min
|
74
72
|
end
|
75
73
|
|
76
|
-
def has_cached_counter?(reflection = reflection)
|
74
|
+
def has_cached_counter?(reflection = reflection())
|
77
75
|
owner.attribute_present?(cached_counter_attribute_name(reflection))
|
78
76
|
end
|
79
77
|
|
80
|
-
def cached_counter_attribute_name(reflection = reflection)
|
78
|
+
def cached_counter_attribute_name(reflection = reflection())
|
81
79
|
options[:counter_cache] || "#{reflection.name}_count"
|
82
80
|
end
|
83
81
|
|
84
|
-
def update_counter(difference, reflection = reflection)
|
82
|
+
def update_counter(difference, reflection = reflection())
|
85
83
|
if has_cached_counter?(reflection)
|
86
84
|
counter = cached_counter_attribute_name(reflection)
|
87
85
|
owner.class.update_counters(owner.id, counter => difference)
|
@@ -100,9 +98,10 @@ module ActiveRecord
|
|
100
98
|
# it will be decremented twice.
|
101
99
|
#
|
102
100
|
# Hence this method.
|
103
|
-
def inverse_updates_counter_cache?(reflection = reflection)
|
101
|
+
def inverse_updates_counter_cache?(reflection = reflection())
|
104
102
|
counter_name = cached_counter_attribute_name(reflection)
|
105
|
-
reflection.klass.
|
103
|
+
reflection.klass._reflections.values.any? { |inverse_reflection|
|
104
|
+
:belongs_to == inverse_reflection.macro &&
|
106
105
|
inverse_reflection.counter_cache_column == counter_name
|
107
106
|
}
|
108
107
|
end
|
@@ -110,10 +109,10 @@ module ActiveRecord
|
|
110
109
|
# Deletes the records according to the <tt>:dependent</tt> option.
|
111
110
|
def delete_records(records, method)
|
112
111
|
if method == :destroy
|
113
|
-
records.each
|
112
|
+
records.each(&:destroy!)
|
114
113
|
update_counter(-records.length) unless inverse_updates_counter_cache?
|
115
114
|
else
|
116
|
-
if records == :all
|
115
|
+
if records == :all || !reflection.klass.primary_key
|
117
116
|
scope = self.scope
|
118
117
|
else
|
119
118
|
scope = self.scope.where(reflection.klass.primary_key => records)
|
@@ -128,7 +127,11 @@ module ActiveRecord
|
|
128
127
|
end
|
129
128
|
|
130
129
|
def foreign_key_present?
|
131
|
-
|
130
|
+
if reflection.klass.primary_key
|
131
|
+
owner.attribute_present?(reflection.association_primary_key)
|
132
|
+
else
|
133
|
+
false
|
134
|
+
end
|
132
135
|
end
|
133
136
|
end
|
134
137
|
end
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
elsif loaded?
|
23
23
|
target.size
|
24
24
|
else
|
25
|
-
|
25
|
+
super
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -30,7 +30,6 @@ module ActiveRecord
|
|
30
30
|
unless owner.new_record?
|
31
31
|
records.flatten.each do |record|
|
32
32
|
raise_on_type_mismatch!(record)
|
33
|
-
record.save! if record.new_record?
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
@@ -40,7 +39,7 @@ module ActiveRecord
|
|
40
39
|
def concat_records(records)
|
41
40
|
ensure_not_nested
|
42
41
|
|
43
|
-
records = super
|
42
|
+
records = super(records, true)
|
44
43
|
|
45
44
|
if owner.new_record? && records
|
46
45
|
records.flatten.each do |record|
|
@@ -84,12 +83,22 @@ module ActiveRecord
|
|
84
83
|
@through_records[record.object_id] ||= begin
|
85
84
|
ensure_mutable
|
86
85
|
|
87
|
-
through_record = through_association.build
|
86
|
+
through_record = through_association.build(*options_for_through_record)
|
88
87
|
through_record.send("#{source_reflection.name}=", record)
|
89
88
|
through_record
|
90
89
|
end
|
91
90
|
end
|
92
91
|
|
92
|
+
def options_for_through_record
|
93
|
+
[through_scope_attributes]
|
94
|
+
end
|
95
|
+
|
96
|
+
def through_scope_attributes
|
97
|
+
scope.where_values_hash(through_association.reflection.name.to_s).
|
98
|
+
except!(through_association.reflection.foreign_key,
|
99
|
+
through_association.reflection.klass.inheritance_column)
|
100
|
+
end
|
101
|
+
|
93
102
|
def save_through_record(record)
|
94
103
|
build_through_record(record).save!
|
95
104
|
ensure
|
@@ -140,7 +149,21 @@ module ActiveRecord
|
|
140
149
|
|
141
150
|
case method
|
142
151
|
when :destroy
|
143
|
-
|
152
|
+
if scope.klass.primary_key
|
153
|
+
count = scope.destroy_all.length
|
154
|
+
else
|
155
|
+
scope.to_a.each do |record|
|
156
|
+
record.run_callbacks :destroy
|
157
|
+
end
|
158
|
+
|
159
|
+
arel = scope.arel
|
160
|
+
|
161
|
+
stmt = Arel::DeleteManager.new arel.engine
|
162
|
+
stmt.from scope.klass.arel_table
|
163
|
+
stmt.wheres = arel.constraints
|
164
|
+
|
165
|
+
count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
|
166
|
+
end
|
144
167
|
when :nullify
|
145
168
|
count = scope.update_all(source_reflection.foreign_key => nil)
|
146
169
|
else
|
@@ -164,7 +187,11 @@ module ActiveRecord
|
|
164
187
|
def through_records_for(record)
|
165
188
|
attributes = construct_join_attributes(record)
|
166
189
|
candidates = Array.wrap(through_association.target)
|
167
|
-
candidates.find_all
|
190
|
+
candidates.find_all do |c|
|
191
|
+
attributes.all? do |key, value|
|
192
|
+
c.public_send(key) == value
|
193
|
+
end
|
194
|
+
end
|
168
195
|
end
|
169
196
|
|
170
197
|
def delete_through_records(records)
|
@@ -1,128 +1,80 @@
|
|
1
|
+
require 'active_record/associations/join_dependency/join_part'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class JoinDependency # :nodoc:
|
4
6
|
class JoinAssociation < JoinPart # :nodoc:
|
5
|
-
include JoinHelper
|
6
|
-
|
7
7
|
# The reflection of the association represented
|
8
8
|
attr_reader :reflection
|
9
9
|
|
10
|
-
|
11
|
-
# relevant for generating aliases which do not conflict with other joins which are
|
12
|
-
# part of the query.
|
13
|
-
attr_reader :join_dependency
|
14
|
-
|
15
|
-
# A JoinBase instance representing the active record we are joining onto.
|
16
|
-
# (So in Author.has_many :posts, the Author would be that base record.)
|
17
|
-
attr_reader :parent
|
18
|
-
|
19
|
-
# What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
|
20
|
-
attr_accessor :join_type
|
21
|
-
|
22
|
-
# These implement abstract methods from the superclass
|
23
|
-
attr_reader :aliased_prefix
|
24
|
-
|
25
|
-
attr_reader :tables
|
26
|
-
|
27
|
-
delegate :options, :through_reflection, :source_reflection, :chain, :to => :reflection
|
28
|
-
delegate :table, :table_name, :to => :parent, :prefix => :parent
|
29
|
-
delegate :alias_tracker, :to => :join_dependency
|
30
|
-
|
31
|
-
alias :alias_suffix :parent_table_name
|
10
|
+
attr_accessor :tables
|
32
11
|
|
33
|
-
def initialize(reflection,
|
34
|
-
reflection.
|
35
|
-
|
36
|
-
if reflection.options[:polymorphic]
|
37
|
-
raise EagerLoadPolymorphicError.new(reflection)
|
38
|
-
end
|
39
|
-
|
40
|
-
super(reflection.klass)
|
12
|
+
def initialize(reflection, children)
|
13
|
+
super(reflection.klass, children)
|
41
14
|
|
42
15
|
@reflection = reflection
|
43
|
-
@
|
44
|
-
@parent = parent
|
45
|
-
@join_type = Arel::InnerJoin
|
46
|
-
@aliased_prefix = "t#{ join_dependency.join_parts.size }"
|
47
|
-
@tables = construct_tables.reverse
|
16
|
+
@tables = nil
|
48
17
|
end
|
49
18
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
other.parent == parent
|
19
|
+
def match?(other)
|
20
|
+
return true if self == other
|
21
|
+
super && reflection == other.reflection
|
54
22
|
end
|
55
23
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
when JoinBase
|
60
|
-
parent.base_klass == join_part.base_klass
|
61
|
-
else
|
62
|
-
parent == join_part
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
24
|
+
def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
|
25
|
+
joins = []
|
26
|
+
tables = tables.reverse
|
66
27
|
|
67
|
-
|
68
|
-
|
69
|
-
foreign_table = parent_table
|
70
|
-
foreign_klass = parent.base_klass
|
28
|
+
scope_chain_index = 0
|
29
|
+
scope_chain = scope_chain.reverse
|
71
30
|
|
72
31
|
# The chain starts with the target table, but we want to end with it here (makes
|
73
32
|
# more sense in this context), so we reverse
|
74
|
-
chain.
|
33
|
+
chain.reverse_each do |reflection|
|
75
34
|
table = tables.shift
|
35
|
+
klass = reflection.klass
|
76
36
|
|
77
37
|
case reflection.source_macro
|
78
38
|
when :belongs_to
|
79
39
|
key = reflection.association_primary_key
|
80
40
|
foreign_key = reflection.foreign_key
|
81
|
-
when :has_and_belongs_to_many
|
82
|
-
# Join the join table first...
|
83
|
-
manager.from(join(
|
84
|
-
table,
|
85
|
-
table[reflection.foreign_key].
|
86
|
-
eq(foreign_table[reflection.active_record_primary_key])
|
87
|
-
))
|
88
|
-
|
89
|
-
foreign_table, table = table, tables.shift
|
90
|
-
|
91
|
-
key = reflection.association_primary_key
|
92
|
-
foreign_key = reflection.association_foreign_key
|
93
41
|
else
|
94
42
|
key = reflection.foreign_key
|
95
43
|
foreign_key = reflection.active_record_primary_key
|
96
44
|
end
|
97
45
|
|
98
|
-
constraint = build_constraint(
|
46
|
+
constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
|
99
47
|
|
100
|
-
scope_chain_items = scope_chain[
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
ActiveRecord::Relation.
|
105
|
-
|
106
|
-
]
|
48
|
+
scope_chain_items = scope_chain[scope_chain_index].map do |item|
|
49
|
+
if item.is_a?(Relation)
|
50
|
+
item
|
51
|
+
else
|
52
|
+
ActiveRecord::Relation.create(klass, table).instance_exec(node, &item)
|
53
|
+
end
|
107
54
|
end
|
55
|
+
scope_chain_index += 1
|
108
56
|
|
109
|
-
scope_chain_items
|
57
|
+
scope_chain_items.concat [klass.send(:build_default_scope, ActiveRecord::Relation.create(klass, table))].compact
|
110
58
|
|
111
|
-
scope_chain_items.
|
112
|
-
|
113
|
-
|
114
|
-
end
|
59
|
+
rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right|
|
60
|
+
left.merge right
|
61
|
+
end
|
115
62
|
|
116
|
-
|
63
|
+
if reflection.type
|
64
|
+
constraint = constraint.and table[reflection.type].eq foreign_klass.base_class.name
|
117
65
|
end
|
118
66
|
|
119
|
-
|
67
|
+
if rel && !rel.arel.constraints.empty?
|
68
|
+
constraint = constraint.and rel.arel.constraints
|
69
|
+
end
|
70
|
+
|
71
|
+
joins << table.create_join(table, table.create_on(constraint), join_type)
|
120
72
|
|
121
73
|
# The current table in this iteration becomes the foreign table in the next
|
122
|
-
foreign_table, foreign_klass = table,
|
74
|
+
foreign_table, foreign_klass = table, klass
|
123
75
|
end
|
124
76
|
|
125
|
-
|
77
|
+
joins
|
126
78
|
end
|
127
79
|
|
128
80
|
# Builds equality condition.
|
@@ -134,42 +86,32 @@ module ActiveRecord
|
|
134
86
|
# end
|
135
87
|
#
|
136
88
|
# If I execute `Physician.joins(:appointments).to_a` then
|
137
|
-
# reflection
|
138
|
-
# table
|
139
|
-
# key
|
140
|
-
# foreign_table
|
141
|
-
# foreign_key
|
89
|
+
# reflection # => #<ActiveRecord::Reflection::AssociationReflection @macro=:has_many ...>
|
90
|
+
# table # => #<Arel::Table @name="appointments" ...>
|
91
|
+
# key # => physician_id
|
92
|
+
# foreign_table # => #<Arel::Table @name="physicians" ...>
|
93
|
+
# foreign_key # => id
|
142
94
|
#
|
143
|
-
def build_constraint(
|
95
|
+
def build_constraint(klass, table, key, foreign_table, foreign_key)
|
144
96
|
constraint = table[key].eq(foreign_table[foreign_key])
|
145
97
|
|
146
|
-
if
|
98
|
+
if klass.finder_needs_type_condition?
|
147
99
|
constraint = table.create_and([
|
148
100
|
constraint,
|
149
|
-
|
101
|
+
klass.send(:type_condition, table)
|
150
102
|
])
|
151
103
|
end
|
152
104
|
|
153
105
|
constraint
|
154
106
|
end
|
155
107
|
|
156
|
-
def join_relation(joining_relation)
|
157
|
-
self.join_type = Arel::OuterJoin
|
158
|
-
joining_relation.joins(self)
|
159
|
-
end
|
160
|
-
|
161
108
|
def table
|
162
|
-
tables.
|
109
|
+
tables.first
|
163
110
|
end
|
164
111
|
|
165
112
|
def aliased_table_name
|
166
113
|
table.table_alias || table.name
|
167
114
|
end
|
168
|
-
|
169
|
-
def scope_chain
|
170
|
-
@scope_chain ||= reflection.scope_chain.reverse
|
171
|
-
end
|
172
|
-
|
173
115
|
end
|
174
116
|
end
|
175
117
|
end
|
@@ -1,18 +1,16 @@
|
|
1
|
+
require 'active_record/associations/join_dependency/join_part'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class JoinDependency # :nodoc:
|
4
6
|
class JoinBase < JoinPart # :nodoc:
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
def aliased_prefix
|
11
|
-
"t0"
|
7
|
+
def match?(other)
|
8
|
+
return true if self == other
|
9
|
+
super && base_klass == other.base_klass
|
12
10
|
end
|
13
11
|
|
14
12
|
def table
|
15
|
-
|
13
|
+
base_klass.arel_table
|
16
14
|
end
|
17
15
|
|
18
16
|
def aliased_table_name
|
@@ -8,34 +8,36 @@ module ActiveRecord
|
|
8
8
|
# operations (for example a has_and_belongs_to_many JoinAssociation would result in
|
9
9
|
# two; one for the join table and one for the target table).
|
10
10
|
class JoinPart # :nodoc:
|
11
|
+
include Enumerable
|
12
|
+
|
11
13
|
# The Active Record class which this join part is associated 'about'; for a JoinBase
|
12
14
|
# this is the actual base model, for a JoinAssociation this is the target model of the
|
13
15
|
# association.
|
14
|
-
attr_reader :base_klass
|
16
|
+
attr_reader :base_klass, :children
|
15
17
|
|
16
|
-
delegate :table_name, :column_names, :primary_key, :
|
18
|
+
delegate :table_name, :column_names, :primary_key, :to => :base_klass
|
17
19
|
|
18
|
-
def initialize(base_klass)
|
20
|
+
def initialize(base_klass, children)
|
19
21
|
@base_klass = base_klass
|
20
|
-
@cached_record = {}
|
21
22
|
@column_names_with_alias = nil
|
23
|
+
@children = children
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
25
|
-
|
26
|
+
def name
|
27
|
+
reflection.name
|
26
28
|
end
|
27
29
|
|
28
|
-
def
|
29
|
-
|
30
|
+
def match?(other)
|
31
|
+
self.class == other.class
|
30
32
|
end
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
def each(&block)
|
35
|
+
yield self
|
36
|
+
children.each { |child| child.each(&block) }
|
35
37
|
end
|
36
38
|
|
37
|
-
#
|
38
|
-
def
|
39
|
+
# An Arel::Table for the active_record
|
40
|
+
def table
|
39
41
|
raise NotImplementedError
|
40
42
|
end
|
41
43
|
|
@@ -44,24 +46,7 @@ module ActiveRecord
|
|
44
46
|
raise NotImplementedError
|
45
47
|
end
|
46
48
|
|
47
|
-
|
48
|
-
def aliased_primary_key
|
49
|
-
"#{aliased_prefix}_r0"
|
50
|
-
end
|
51
|
-
|
52
|
-
# An array of [column_name, alias] pairs for the table
|
53
|
-
def column_names_with_alias
|
54
|
-
unless @column_names_with_alias
|
55
|
-
@column_names_with_alias = []
|
56
|
-
|
57
|
-
([primary_key] + (column_names - [primary_key])).compact.each_with_index do |column_name, i|
|
58
|
-
@column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
@column_names_with_alias
|
62
|
-
end
|
63
|
-
|
64
|
-
def extract_record(row)
|
49
|
+
def extract_record(row, column_names_with_alias)
|
65
50
|
# This code is performance critical as it is called per row.
|
66
51
|
# see: https://github.com/rails/rails/pull/12185
|
67
52
|
hash = {}
|
@@ -78,12 +63,8 @@ module ActiveRecord
|
|
78
63
|
hash
|
79
64
|
end
|
80
65
|
|
81
|
-
def
|
82
|
-
row
|
83
|
-
end
|
84
|
-
|
85
|
-
def instantiate(row)
|
86
|
-
@cached_record[record_id(row)] ||= base_klass.instantiate(extract_record(row))
|
66
|
+
def instantiate(row, aliases)
|
67
|
+
base_klass.instantiate(extract_record(row, aliases))
|
87
68
|
end
|
88
69
|
end
|
89
70
|
end
|