I have a rake task that looks like this:
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
Yet when I run it, I get this:
$ rake cleanup_snippets_with_empty_diffs
rake aborted!
ActiveRecord::ReadOnlyRecord: Diff is marked as readonly
What could be the cause of this?
Edit 1
Note that my Snippet.rb
model looks like this:
class Snippet < ApplicationRecord
has_many :diffs, dependent: :destroy
end
And Diff.rb
like this:
class Diff < ApplicationRecord
belongs_to :snippet
end
With includes
, Rails will determine whether to use multiple queries (using preload
) or a single left outer join query (using eager_load
). In your case, because your where clause is on the association, Rails will use eager_load
and therefore a LEFT OUTER JOIN. Also note that associations loaded via a join are marked as readonly
and is the cause of the error you're receiving. The solution is to switch includes
to left_joins
and set readonly(false)
prior to calling destroy_all
.
Snippet.left_joins(:diffs).readonly(false).where(diffs: { body: "<div class=\"diff\"></div>"}).destroy_all
NOTE
I originally thought you could do
Snippet.includes(:diffs).readonly(false).where(diffs: { body: "<div class=\"diff\"></div>"}).destroy_all
but this doesn't work for some reason (and don't have enough time to investigate atm). In any case, since using includes
would result in a LEFT OUTER JOIN anyways, you can use the above solution to get the desired outcome.