Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
990a4dbb
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
990a4dbb
编写于
7月 04, 2017
作者:
R
Rafael França
提交者:
GitHub
7月 04, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #29413 from kamipo/fix_association_with_scope_including_joins
Fix association with scope including joins
上级
f01eb5b9
db3ff259
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
60 addition
and
70 deletion
+60
-70
activerecord/CHANGELOG.md
activerecord/CHANGELOG.md
+6
-0
activerecord/lib/active_record/associations/join_dependency/join_association.rb
...e_record/associations/join_dependency/join_association.rb
+10
-4
activerecord/lib/active_record/associations/preloader.rb
activerecord/lib/active_record/associations/preloader.rb
+0
-3
activerecord/lib/active_record/associations/preloader/association.rb
...d/lib/active_record/associations/preloader/association.rb
+15
-53
activerecord/lib/active_record/associations/preloader/through_association.rb
...tive_record/associations/preloader/through_association.rb
+10
-3
activerecord/lib/active_record/reflection.rb
activerecord/lib/active_record/reflection.rb
+11
-7
activerecord/test/cases/associations/eager_test.rb
activerecord/test/cases/associations/eager_test.rb
+5
-0
activerecord/test/models/club.rb
activerecord/test/models/club.rb
+2
-0
activerecord/test/models/member.rb
activerecord/test/models/member.rb
+1
-0
未找到文件。
activerecord/CHANGELOG.md
浏览文件 @
990a4dbb
*
Fix eager loading/preloading association with scope including joins.
Fixes #28324.
*Ryuta Kamizono*
*
Fix transactions to apply state to child transactions
Previously if you had a nested transaction and the outer transaction was rolledback the record from the
...
...
activerecord/lib/active_record/associations/join_dependency/join_association.rb
浏览文件 @
990a4dbb
...
...
@@ -34,13 +34,19 @@ def join_constraints(foreign_table, foreign_klass, join_type, tables, chain)
table
=
tables
.
shift
klass
=
reflection
.
klass
join_scope
=
reflection
.
join_scope
(
table
,
foreign_table
,
foreign_klass
)
binds
.
concat
join_scope
.
bound_attributes
constraint
=
join_scope
.
arel
.
constraints
constraint
=
reflection
.
build_join_constraint
(
table
,
foreign_table
)
joins
<<
table
.
create_join
(
table
,
table
.
create_on
(
constraint
),
join_type
)
join_scope
=
reflection
.
join_scope
(
table
,
foreign_klass
)
if
join_scope
.
arel
.
constraints
.
any?
binds
.
concat
join_scope
.
bound_attributes
joins
.
concat
join_scope
.
arel
.
join_sources
right
=
joins
.
last
.
right
right
.
expr
=
right
.
expr
.
and
(
join_scope
.
arel
.
constraints
)
end
# The current table in this iteration becomes the foreign table in the next
foreign_table
,
foreign_klass
=
table
,
klass
end
...
...
activerecord/lib/active_record/associations/preloader.rb
浏览文件 @
990a4dbb
...
...
@@ -54,8 +54,6 @@ class Preloader #:nodoc:
autoload
:BelongsTo
,
"active_record/associations/preloader/belongs_to"
end
NULL_RELATION
=
Struct
.
new
(
:values
,
:where_clause
,
:joins_values
).
new
({},
Relation
::
WhereClause
.
empty
,
[])
# Eager loads the named associations for the given Active Record record(s).
#
# In this description, 'association name' shall refer to the name passed
...
...
@@ -93,7 +91,6 @@ class Preloader #:nodoc:
def
preload
(
records
,
associations
,
preload_scope
=
nil
)
records
=
Array
.
wrap
(
records
).
compact
.
uniq
associations
=
Array
.
wrap
(
associations
)
preload_scope
=
preload_scope
||
NULL_RELATION
if
records
.
empty?
[]
...
...
activerecord/lib/active_record/associations/preloader/association.rb
浏览文件 @
990a4dbb
...
...
@@ -11,7 +11,6 @@ def initialize(klass, owners, reflection, preload_scope)
@reflection
=
reflection
@preload_scope
=
preload_scope
@model
=
owners
.
first
&&
owners
.
first
.
class
@scope
=
nil
@preloaded_records
=
[]
end
...
...
@@ -23,29 +22,11 @@ def preload(preloader)
raise
NotImplementedError
end
def
scope
@scope
||=
build_scope
end
def
records_for
(
ids
)
scope
.
where
(
association_key_name
=>
ids
)
end
def
table
klass
.
arel_table
end
# The name of the key on the associated records
def
association_key_name
raise
NotImplementedError
end
# This is overridden by HABTM as the condition should be on the foreign_key column in
# the join table
def
association_key
klass
.
arel_attribute
(
association_key_name
,
table
)
end
# The name of the key on the model which declares the association
def
owner_key_name
raise
NotImplementedError
...
...
@@ -114,54 +95,35 @@ def load_records(&block)
# Make several smaller queries if necessary or make one query if the adapter supports it
slices
=
owner_keys
.
each_slice
(
klass
.
connection
.
in_clause_length
||
owner_keys
.
size
)
@preloaded_records
=
slices
.
flat_map
do
|
slice
|
records_for
(
slice
).
load
(
&
block
)
records_for
(
slice
,
&
block
)
end
@preloaded_records
.
group_by
do
|
record
|
convert_key
(
record
[
association_key_name
])
end
end
def
records_for
(
ids
,
&
block
)
scope
.
where
(
association_key_name
=>
ids
).
load
(
&
block
)
end
def
scope
@scope
||=
build_scope
end
def
reflection_scope
@reflection_scope
||=
reflection
.
scope_for
(
klass
)
end
def
build_scope
scope
=
klass
.
unscoped
values
=
reflection_scope
.
values
preload_values
=
preload_scope
.
values
scope
.
where_clause
=
reflection_scope
.
where_clause
+
preload_scope
.
where_clause
scope
.
references_values
=
Array
(
values
[
:references
])
+
Array
(
preload_values
[
:references
])
if
preload_values
[
:select
]
||
values
[
:select
]
scope
.
_select!
(
preload_values
[
:select
]
||
values
[
:select
])
end
scope
.
includes!
preload_values
[
:includes
]
||
values
[
:includes
]
if
preload_scope
.
joins_values
.
any?
scope
.
joins!
(
preload_scope
.
joins_values
)
else
scope
.
joins!
(
reflection_scope
.
joins_values
)
end
if
order_values
=
preload_values
[
:order
]
||
values
[
:order
]
scope
.
order!
(
order_values
)
end
if
preload_values
[
:reordering
]
||
values
[
:reordering
]
scope
.
reordering_value
=
true
end
if
preload_values
[
:readonly
]
||
values
[
:readonly
]
scope
.
readonly!
end
scope
=
klass
.
default_scoped
if
options
[
:as
]
scope
.
where!
(
klass
.
table_name
=>
{
reflection
.
type
=>
model
.
base_class
.
sti_name
}
)
if
reflection
.
type
scope
.
where!
(
reflection
.
type
=>
model
.
base_class
.
sti_name
)
end
scope
.
unscope_values
=
Array
(
values
[
:unscope
])
+
Array
(
preload_values
[
:unscope
])
klass
.
default_scoped
.
merge
(
scope
)
scope
.
merge!
(
reflection_scope
)
scope
.
merge!
(
preload_scope
)
if
preload_scope
scope
end
end
end
...
...
activerecord/lib/active_record/associations/preloader/through_association.rb
浏览文件 @
990a4dbb
...
...
@@ -79,17 +79,24 @@ def reset_association(owners, association_name, through_scope)
def
through_scope
scope
=
through_reflection
.
klass
.
unscoped
values
=
reflection_scope
.
values
if
options
[
:source_type
]
scope
.
where!
reflection
.
foreign_type
=>
options
[
:source_type
]
else
unless
reflection_scope
.
where_clause
.
empty?
scope
.
includes_values
=
Array
(
reflection_scope
.
values
[
:includes
]
||
options
[
:source
])
scope
.
includes_values
=
Array
(
values
[
:includes
]
||
options
[
:source
])
scope
.
where_clause
=
reflection_scope
.
where_clause
if
joins
=
values
[
:joins
]
scope
.
joins!
(
source_reflection
.
name
=>
joins
)
end
if
left_outer_joins
=
values
[
:left_outer_joins
]
scope
.
left_outer_joins!
(
source_reflection
.
name
=>
left_outer_joins
)
end
end
scope
.
references!
reflection_scope
.
values
[
:references
]
if
scope
.
eager_loading?
&&
order_values
=
reflection_scope
.
values
[
:order
]
scope
.
references!
values
[
:references
]
if
scope
.
eager_loading?
&&
order_values
=
values
[
:order
]
scope
=
scope
.
order
(
order_values
)
end
end
...
...
activerecord/lib/active_record/reflection.rb
浏览文件 @
990a4dbb
...
...
@@ -185,19 +185,23 @@ def scope_chain
end
deprecate
:scope_chain
def
join_scope
(
table
,
foreign_table
,
foreign_klass
)
predicate_builder
=
predicate_builder
(
table
)
scope_chain_items
=
join_scopes
(
table
,
predicate_builder
)
klass_scope
=
klass_join_scope
(
table
,
predicate_builder
)
def
build_join_constraint
(
table
,
foreign_table
)
key
=
join_keys
.
key
foreign_key
=
join_keys
.
foreign_key
klass_scope
.
where!
(
table
[
key
].
eq
(
foreign_table
[
foreign_key
])
)
constraint
=
table
[
key
].
eq
(
foreign_table
[
foreign_key
]
)
if
klass
.
finder_needs_type_condition?
klass_scope
.
where!
(
klass
.
send
(
:type_condition
,
table
))
table
.
create_and
([
constraint
,
klass
.
send
(
:type_condition
,
table
)])
else
constraint
end
end
def
join_scope
(
table
,
foreign_klass
)
predicate_builder
=
predicate_builder
(
table
)
scope_chain_items
=
join_scopes
(
table
,
predicate_builder
)
klass_scope
=
klass_join_scope
(
table
,
predicate_builder
)
if
type
klass_scope
.
where!
(
type
=>
foreign_klass
.
base_class
.
sti_name
)
...
...
activerecord/test/cases/associations/eager_test.rb
浏览文件 @
990a4dbb
...
...
@@ -68,6 +68,11 @@ def test_loading_conditions_with_or
"expected to find only david's posts"
end
def
test_loading_with_scope_including_joins
assert_equal
clubs
(
:boring_club
),
Member
.
preload
(
:general_club
).
find
(
1
).
general_club
assert_equal
clubs
(
:boring_club
),
Member
.
eager_load
(
:general_club
).
find
(
1
).
general_club
end
def
test_with_ordering
list
=
Post
.
all
.
merge!
(
includes: :comments
,
order:
"posts.id DESC"
).
to_a
[
:other_by_mary
,
:other_by_bob
,
:misc_by_mary
,
:misc_by_bob
,
:eager_other
,
...
...
activerecord/test/models/club.rb
浏览文件 @
990a4dbb
...
...
@@ -8,6 +8,8 @@ class Club < ActiveRecord::Base
has_many
:favourites
,
->
{
where
(
memberships:
{
favourite:
true
})
},
through: :memberships
,
source: :member
scope
:general
,
->
{
left_joins
(
:category
).
where
(
categories:
{
name:
"General"
})
}
private
def
private_method
...
...
activerecord/test/models/member.rb
浏览文件 @
990a4dbb
...
...
@@ -22,6 +22,7 @@ class Member < ActiveRecord::Base
has_many
:organization_member_details_2
,
through: :organization
,
source: :member_details
has_one
:club_category
,
through: :club
,
source: :category
has_one
:general_club
,
->
{
general
},
through: :current_membership
,
source: :club
has_many
:current_memberships
,
->
{
where
favourite:
true
}
has_many
:clubs
,
through: :current_memberships
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录