In my app I create a directory when I create my theme record. This is to store file assets related to the theme. I've always struggled with how to keep the existence of the directory in sync with the lifecycle of the record. This is my current take:
after_create :create_theme_directory
after_rollback :destroy_theme_directory, :on => :create, :if => :id
def directory
Rails.configuration.uploads_root.join('themes', id.to_s)
end
private
def create_theme_directory
FileUtils.mkdir_p directory
end
def destroy_theme_directory
FileUtils.remove_dir directory, :force => true
end
It works well except that Rspec doesn't seem to trigger the removal of the directory when it rolls back theme records after tests.
Is there a best practice for this kind of thing? The idea being that one should never be left with a stray directory without an associated record.
The after_rollback
callback you have defined will only get called if the creating, destroying or updating a record were done through ActiveRecord. When RSpec resets, it doesn't go through ActiveRecord so it doesn't trigger any of the transaction callbacks (after_rollback and after_commit).
You could add another callback that destroys the directory if it still exists:
after_commit :destroy_theme_directory, :on => :destroy
def destroy_theme_directory
if File.directory?(directory)
FileUtils.remove_dir directory, :force => true
end
end
And then trigger both the create and destroy actions in your feature spec:
scenario 'create and destroy' do
visit new_directory_path
#fill_in fields
click_button "Create"
expect(page).to have_content "created"
visit users_path
click_link "Delete" #assuming only directory object exists and you have a delete link in your directory index page
end
In this way, you trigger both the create and destroy actions in your specs so you don't need to do any clean-up.
The other option is to manually remove the directory in the spec where you test its creation.
#assuming you have model spec for testing that directory is created
it 'creates corresponding directory'
directory.create
expect(File.directory?(directory)).to eq true
# the line below is just for cleanup. No need to do it in an after_all block if it only needs to be done for a few specs
FileUtils.remove_dir directory, :force => true
end
Hope that helps.
Really interesting question for which I have an interest of my own since I am currently developing an application where files are being uploaded and converted.
Not an expert on RSpec at all, but I suppose it is very much database orientated and leaves it up to the user to clean up after himself if it's not related to the database (like creation of folders/updating images/initiating an external interface).
Found this example on how to use after(:all) for the cleanup with RSepc and carrierwave testing - similar to my initial though.
Another alternative is more pragmatic and probably more limited when it comes to testing. Have a backup file for your target structure available and restore it after tests have been completed.
I am indeed interested if anyone has a better method.
Hope this helps! Eugen
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With