Rails 嵌套连接 - Rails 4
Rails Nested Joins - Rails 4
我有3个模型。
class Saving
has_many :contributions
end
class Contribution
belongs_to :saving
has_many :deposits
end
class Deposit
belongs_to :contribution
end
现在我想查询所有的储蓄和贡献,并计算deposits.amount的总和。我也想要没有存款的记录。
如果我使用
Saving.joins(contributions: [:deposit])
这将给我所有有存款的储蓄。但我想加入贡献和 left_outer_joins 存款。
我怎样才能做到这一点?我正在使用 Rails 4. 所以我无法做到
Saving.left_outer_joins(contributions: [:deposit]).
在遗留应用程序中进行外部连接的最直接的方法是使用 SQL 字符串:
Saving.select(
'savings.*',
'SUM(deposits.amount) AS total_deposits'
)
.joins(:contributions)
.joins(%q{
LEFT OUTER JOINS depostits
ON depostits.contribution_id = contributions.id
})
您也可以(误)使用 .includes
,因为它执行外部联接:
class Saving
has_many :contributions
has_many :deposits, through: :contributions
end
Saving.includes(:deposits)
.references(:deposits) # forces a single query
.joins(:contributions) # optional - creates an additional inner join
.select(
'savings.*',
'SUM(deposits.amount) AS total_deposits'
)
你也可以使用 Arel:
module LegacyOuterJoiner
# clunky hack for outer joins in legacy apps.
def arel_outer_joins(association_name, fkey = nil)
raise "This method is obsolete! Use left_joins!" if respond_to?(:left_joins)
other_model = reflect_on_association(association_name).klass
right = other_model.arel_table
fkey ||= "#{other_model.model_name.singular}_id".intern
arel_table.joins(right, Arel::Nodes::OuterJoin)
.on(arel_table[fkey].eq(right[:id]))
.join_sources
end
end
class Deposit
extend LegacyOuterJoiner
end
Saving.select(
Saving.arel_table[Arel.star],
Deposit.arel_table[:amount].sum.as('total_deposits')
)
.joins(:contributions)
.joins(Deposit.arel_outer_joins(:contribution))
我有3个模型。
class Saving
has_many :contributions
end
class Contribution
belongs_to :saving
has_many :deposits
end
class Deposit
belongs_to :contribution
end
现在我想查询所有的储蓄和贡献,并计算deposits.amount的总和。我也想要没有存款的记录。
如果我使用
Saving.joins(contributions: [:deposit])
这将给我所有有存款的储蓄。但我想加入贡献和 left_outer_joins 存款。
我怎样才能做到这一点?我正在使用 Rails 4. 所以我无法做到
Saving.left_outer_joins(contributions: [:deposit]).
在遗留应用程序中进行外部连接的最直接的方法是使用 SQL 字符串:
Saving.select(
'savings.*',
'SUM(deposits.amount) AS total_deposits'
)
.joins(:contributions)
.joins(%q{
LEFT OUTER JOINS depostits
ON depostits.contribution_id = contributions.id
})
您也可以(误)使用 .includes
,因为它执行外部联接:
class Saving
has_many :contributions
has_many :deposits, through: :contributions
end
Saving.includes(:deposits)
.references(:deposits) # forces a single query
.joins(:contributions) # optional - creates an additional inner join
.select(
'savings.*',
'SUM(deposits.amount) AS total_deposits'
)
你也可以使用 Arel:
module LegacyOuterJoiner
# clunky hack for outer joins in legacy apps.
def arel_outer_joins(association_name, fkey = nil)
raise "This method is obsolete! Use left_joins!" if respond_to?(:left_joins)
other_model = reflect_on_association(association_name).klass
right = other_model.arel_table
fkey ||= "#{other_model.model_name.singular}_id".intern
arel_table.joins(right, Arel::Nodes::OuterJoin)
.on(arel_table[fkey].eq(right[:id]))
.join_sources
end
end
class Deposit
extend LegacyOuterJoiner
end
Saving.select(
Saving.arel_table[Arel.star],
Deposit.arel_table[:amount].sum.as('total_deposits')
)
.joins(:contributions)
.joins(Deposit.arel_outer_joins(:contribution))