我有一个rake任务,如下所示:
desc "Cleanup Snippets with Empty Diffs"
task cleanup_snippets_with_empty_diffs: :environment do
Snippet.includes(:diffs).where(diffs: { body: "<div class=\"diff\"></div>"}).destroy_all
end
然而,当我运行它时,我明白了:
$ rake cleanup_snippets_with_empty_diffs
rake aborted!
ActiveRecord::ReadOnlyRecord: Diff is marked as readonly
这可能是什么原因?
修改1
请注意,我的Snippet.rb
模型如下所示:
class Snippet < ApplicationRecord
has_many :diffs, dependent: :destroy
end
Diff.rb
就像这样:
class Diff < ApplicationRecord
belongs_to :snippet
end
答案 0 :(得分:5)
使用includes
,Rails将确定是使用多个查询(使用preload
)还是使用单个左外连接查询(使用eager_load
)。在您的情况下,因为您的where子句在关联上,Rails将使用eager_load
,因此使用LEFT OUTER JOIN。另请注意,通过连接加载的关联标记为readonly
,并且是您收到错误的原因。解决方案是在调用includes
之前将left_joins
切换为readonly(false)
并设置destroy_all
。
Snippet.left_joins(:diffs).readonly(false).where(diffs: { body: "<div class=\"diff\"></div>"}).destroy_all
注意强>
我原本以为你可以做到
Snippet.includes(:diffs).readonly(false).where(diffs: { body: "<div class=\"diff\"></div>"}).destroy_all
但由于某种原因(并且没有足够的时间来调查atm)这不起作用。在任何情况下,由于使用includes
无论如何都会导致LEFT OUTER JOIN,您可以使用上述解决方案来获得所需的结果。