Rails carrierwave testing - how to remove file after test?

人走茶凉 提交于 2019-12-23 01:16:32

问题


I am testing the carrierwave upload functionality using rspec and capybara. I have something like:

describe "attachment" do
    let(:local_path)  { "my/file/path" }
    before do
      attach_file('Attachment file', local_path)
      click_button "Save changes"       
    end

    specify {user.attachment.should_not be_nil}
    it { should have_link('attachment', href: user.attachment_url) }
end

And this works great. The problem is that after testing the uploaded image remains in my public/uploads directory. How can I remove it after the test is done? I tried something like this:

after do
   user.remove_attachment!
end

but it did not work.


回答1:


You're not the only one having issues to delete the files in carrierwave.

I ended up doing:

user.remove_attachment = true
user.save

I got this tip reading this.




回答2:


Ha! I found the answer to this today.

The auto-removal of the downloaded file is done in an after_commit hook. These do not get run by default in rails tests. I never would have guessed that.

It is however documented offhandedly in a postscript note here: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#method-i-after_commit

I discovered this by deep diving into the carrierwave code with a debugger and just happened to notice it in the comments above the source code to after_commit when I stepped into it.

Thank goodness ruby libraries are not stripped of comments at runtime like JS. ;)

The workaround suggested in the docs is to include the 'test_after_commit' gem in your Gemfile BUT ONLY IN THE TEST ENVIRONMENT.

i.e.

Gemfile:

...
gem 'test_after_commit', :group => :test
...

When I did this, it completely solved the problem for me.

Now, my post-destruction assertions of cleanup pass.




回答3:


The latest CarrierWave documentation for this technique is as follows:

config.after(:suite) do
  if Rails.env.test? 
    FileUtils.rm_rf(Dir["#{Rails.root}/spec/support/uploads"])
  end 
end

Note that the above simply assumes youre using spec/support/uploads/ for images and you dont mind deleting everything in that directory. If you have different locations for each uploader, you may want to derive the upload and cache directories straight from the (factory) model:

config.after(:suite) do
  # Get rid of the linked images
  if Rails.env.test? || Rails.env.cucumber?
    tmp = Factory(:brand)
    store_path = File.dirname(File.dirname(tmp.logo.url))
    temp_path = tmp.logo.cache_dir
    FileUtils.rm_rf(Dir["#{Rails.root}/public/#{store_path}/[^.]*"])
    FileUtils.rm_rf(Dir["#{temp_path}/[^.]*"])
  end
end

or, if you want to delete everything under the CarrierWave root that you set in an initializer, you can do this:

config.after(:suite) do
  # Get rid of the linked images
  if Rails.env.test? || Rails.env.cucumber?
    FileUtils.rm_rf(CarrierWave::Uploader::Base.root)
  end
end



回答4:


A cleaner solution that seems to work for me is the following in spec/support/carrierwave.rb:

uploads_test_path = Rails.root.join('uploads_test')

CarrierWave.configure do |config|
  config.root = uploads_test_path
end

RSpec.configure do |config|
  config.after(:suite) do
    FileUtils.rm_rf(Dir[uploads_test_path])
  end
end

This would set the whole root folder specific to the test environment and delete it all after the suite, so you do not have to worry about store_dir and cache_dir separately.



来源:https://stackoverflow.com/questions/12352062/rails-carrierwave-testing-how-to-remove-file-after-test

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!