Arel UpdateManager with Join 创建无效 SQL - 如何改写?

Arel UpdateManager with Join creates invalid SQL - how to rephrase?

显然有一个 issue in Arel core,其中 Arel::UpdateManager 在对连接执行列更新时不会为更新列生成 table 名称。它导致无效 SQL.

我在 Rails 5.2 应用程序中 运行 加入了这个,其中我有一个 SQL 文字更新语句,我试图在 Arel 中重新表述。

UPDATE observations o, names n
SET o.lifeform = n.lifeform
WHERE o.name_id = n.id
  AND o.lifeform != n.lifeform

在Arel,我写了这个:

names = Name.arel_table
obs = Observation.arel_table
join_source = Arel::Nodes::JoinSource.new(
  obs, [obs.create_join(names)]
)

Arel::UpdateManager.new.
  table(join_source).
  where(obs[:id].eq(names[:id]).
        and(obs[:lifeform].not_eq(names[:lifeform]))).
  set([[obs[:lifeform], names[:lifeform]]])

这个returns:

Mysql2::Error: Column 'lifeform' in field list is ambiguous: 

问题在最后。由此生成的SQL没有指定要设置列的table。

UPDATE `observations` 
INNER JOIN `names` 
SET `lifeform` = `names`.`lifeform` 
WHERE (`observations`.`id` = `names`.`id`) 
AND (`observations`.`lifeform` != `names`.`lifeform`)

在其他地方,Arel 生成的 SQL 通常使用 table 名称限定列以避免歧义。但是 source code for update_manager.rb definitely uses Nodes::UnqualifiedColumn.new(column). (I have added my description 到 GitHub 上的 Arel 问题。)

现在我可能想用其他方式重新表述我的 Arel。有没有办法强制 Arel 引用 table 名称,类似于 connection.quote_table_name?

或者使用 CTE 是否合适?

我猜一种方法是使用 ActiveRecord 的 connection.update_all

names = Arel::Table.new(:names)
Observation.joins(:name).
 where(names[:correct_spelling_id].not_eq(nil)).
  update_all("`observations`.`name_id` = `names`.`correct_spelling_id`")

这会生成所需的 SQL:

UPDATE `observations` 
INNER JOIN `names` 
ON (`observations`.`name_id` = `names`.`correct_spelling_id`) 
  AND (`names`.`correct_spelling_id` IS NOT NULL) 
SET `observations`.`name_id` = `names`.`correct_spelling_id`

我认为这是要走的路。