在这种情况下,Rails 对原始 SQL 的抽象让我抓狂。在 MySQL 中我可以这样做:
UPDATE FROM tasks AS t
LEFT JOIN projects as p
ON t.project_id = p.id
SET t.invoice_id = 7
WHERE p.organization_id == 42
AND t.invoice_id IS NULL
我如何在 Rails 3.0.1 中使用预先加载来做到这一点?我已经尝试了以下所有方法:
Tasks.joins(:project).where('projects.organization_id' => 42, :invoice_id => nil).update_all( :invoice_id => 7 )
以及上述的所有变体。所有要么给出错误,要么没有找到任何东西。
然后我尝试使用 scope
:
Task.scope :find => {:joins => :project, :conditions => ["projects.organization_id == ? AND invoice_id IS NULL", @organization.id] } do
Task.update_all :invoice_id => @invoice.id
end
这个给了我错误 undefined method 'to_sym' for #<Hash:0x1065c6438>
.
我在这上面花了太多时间,只是为了复制一个简单的 SQL 查询。请帮忙!
编辑:绕过 n+1 的临时错误解决方案:
task_ids = Task.select('tasks.id').joins(:project).where('projects.organization_id' => @organization.id, :invoice_id => nil).collect{|t| t.id}
Task.update_all ['invoice_id = ?', @invoice.id], ["id in (#{task_ids.join(',')})"]
最佳答案
"UPDATE FROM"不是标准的 SQL,因此如果 Active Record 不直接支持它也就不足为奇了。然而,Active Record 确实为您提供了一种绕过其抽象并直接发出 SQL 的方法,用于那些您必须执行它不支持的操作的时候。模型内部:
sql = "UPDATE FROM tasks AS t
LEFT JOIN projects as p
ON t.project_id = p.id
SET t.invoice_id = 7
WHERE p.organization_id == 42
AND t.invoice_id IS NULL"
connection.update_sql(sql)
ActiveRecord::Base 也有一个“select_by_sql”方法,让您的非标准选择语句返回常规事件记录模型实例。
关于sql - 在 Rails 中使用连接执行 update_all,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6831069/