RSpec: paranoid2 - не может изменить замороженный хэш
Я работаю над тестами RSpec для моей модели, в которой используется гем paranoid2. Это какая-то паранойя или activ_as_paranoid - перезаписывает.delete и.destroy и некоторые другие своими версиями, которые помечают данные как удаленные, а не удаляя их, пока вы не заставите их с помощью (forced: true)
параметр.
Мое приложение работает нормально, и у меня проблемы только с rspec.
спецификации / модели /slide_spec.rb:
describe Slide do
let (:slide) { build(:slide) }
describe "after .destroy(force: true)" do
before do
slide.save
slide.destroy(force: false)
end
it "is invisible" do
expect{slide.destroy(force: true)}.to_not change(Slide, :count)
end
it "visible if .only_deleted" do
expect{slide.destroy(force: true)}.to change(Slide.only_deleted, :count).by(-1)
end
it "visible if .with_deleted" do
expect{slide.destroy(force: true)}.to change(Slide.with_deleted, :count).by(-1)
end
end
end
вывод rspec:
after .destroy(force: true)
visible if .with_deleted (FAILED - 1)
visible if .only_deleted (FAILED - 2)
is invisible (FAILED - 3)
Failures:
1) Slide after .destroy(force: true) visible if .with_deleted
Failure/Error: expect{slide.destroy(force: true)}.to change(Slide.with_deleted, :count).by(-1)
RuntimeError:
can't modify frozen Hash
# ./spec/models/slide_spec.rb:52:in `block (4 levels) in <top (required)>'
# ./spec/models/slide_spec.rb:52:in `block (3 levels) in <top (required)>'
2) same as above
3) same sa above
/app/model/slide.rb:
class Slide < ActiveRecord::Base
paranoid
...
1 ответ
Это происходит потому, что Rails помечает хэш внутренних атрибутов freeze
после вызова уничтожить на модели. Этот замороженный хеш запрещает дальнейшее изменение объекта: destroy(force: true)
хочет удалить id
, reload
хочет переопределить некоторые атрибуты свежим значением из базы данных - оба потерпят неудачу.
Единственный способ избежать этой проблемы - перезагрузить объект вручную:
describe "after .destroy(force: true)" do
before do
slide.save
slide.destroy(force: false)
@slide = Slide.with_deleted.find(slide.id) # manual reload
end
it "is invisible" do
expect{@slide.destroy(force: true)}.to_not change(Slide, :count)
end
it "visible if .only_deleted" do
expect{@slide.destroy(force: true)}.to change(Slide.only_deleted, :count).by(-1)
end
it "visible if .with_deleted" do
expect{@slide.destroy(force: true)}.to change(Slide.with_deleted, :count).by(-1)
end
end