Search code examples
ruby-on-railsrspecrails-activestorage

RSpec ActiveStorage: Error ActiveRecord::RecordNotFound: Couldn't find ActiveStorage::Blob with 'id'


Hi guys Can I please get some help to figure out what is going wrong with my RSpec test. I been looking all over the internet and haven't found anything that would point to reason why i'm getting this error.

What i'm trying to do is test that an instance variable has some data from the DB. The error is happening when the test reaches the Fabricator that creates the active record and also the ActiveStorage Blob. I have added the database-cleaner gem but not sure of something is messing up with that or i'm missing something when using RSpec, active storage, and DBcleaner.

What is strange is that I have another test that also creates the same Fabricated Object and I dont get the error you will see below. If I comment out the test below the other test runs just fine. Any help would be really appreciated. Been stuck on this for hours :$

UPDATE: I tried to look into what was happening after the graphic fabricator ran and when I looked into the attachments using the attached? methods each of the files were actually attached. All four files came back as attached true. I thought there would be something going on with the cleaner so I added to the rails_helper to purge all the files after each test is done.

config.after(:each) do
 DatabaseCleaner.clean
 ActiveStorage::Attachment.all.each { |attachment| attachment.purge }
end 

This should grab all attachments and delete the attachment and blobs after each test runs. But this didnt do anything. Still not sure what is happening.

Any help would be appreciated.

Thanks :)

ERROR:

1) Dashboard::VendorDashboardsController GET sales Authenticated assigns instance variable with purchases for that store
 Failure/Error: graphic =  Fabricate(:graphic, store:store)
 
 ActiveRecord::RecordNotFound:
   Couldn't find ActiveStorage::Blob with 'id'=1
 # ./spec/controllers/Dashboard/vendor_dashboards_controller_spec.rb:26:in `block (4 levels) in <top (required)>'

RSPEC TEST

it "assigns instance variable with purchases for that store" do
    @user = Fabricate(:user)
    vendor = Fabricate(:vendor, user:@user)
    store = Fabricate(:store, vendor:vendor)
    graphic =  Fabricate(:graphic, store:store)
    purchase_one = Fabricate(:purchase, purchasable_id:graphic.id)
    purchase_two = Fabricate(:purchase, purchasable_id:graphic.id)
    @user.add_role(:vendor)
    login_user(@user)
    get :sales 
    expect(assigns(:sales)).to eq(Purchase.where(store_id:store.id))
end 

FABRICATOR

Fabricator(:graphic)do

store

name "Icon Set"

language "Spanish"

standard_license_price 10.00

business_license_price 100.00

reviewed true

status "Approved"

files_included "PSD, CSS"

category "Vectors"

subject "Characters"

support "3 Month Support"

layered true

high_resolution true

pixel_dimensions "2000x2000"

software_required "Illustrator"

thumbnail_image ActiveStorage::Blob.create_after_upload!(io: File.open(Rails.root.join('spec', 'support', 'assets', 'graphics', 'Advertise.png'), 'rb'), filename: 'Advertise.png',content_type: 'image/png').signed_id

main_image ActiveStorage::Blob.create_after_upload!(io: File.open(Rails.root.join('spec', 'support', 'assets', 'graphics', 'Chat.png'), 'rb'), filename: 'Chat.png',content_type: 'image/png').signed_id

product_images ActiveStorage::Blob.create_after_upload!(io: File.open(Rails.root.join('spec', 'support', 'assets', 'graphics', 'Chat.png'), 'rb'), filename: 'Chat.png',content_type: 'image/png').signed_id

graphic_asset_files ActiveStorage::Blob.create_after_upload!(io: File.open(Rails.root.join('spec', 'support', 'assets', 'graphics', 'test_illustrations.zip'), 'rb'), filename: 'test_illustrations.zip',content_type: 'application/zip').signed_id

description "This is the best graphic design"

end

RAILS HELPER FILE

# This file is copied to spec/ when you run 'rails generate rspec:install'

require 'spec_helper'

ENV['RAILS_ENV'] ||= 'test'

require File.expand_path('../config/environment', __dir__)

# Prevent database truncation if the environment is production

abort("The Rails environment is running in production mode!") if Rails.env.production?

require 'rspec/rails'



begin

ActiveRecord::Migration.maintain_test_schema!

rescue ActiveRecord::PendingMigrationError => e

puts e.to_s.strip

exit 1

end

RSpec.configure do |config|

# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures

config.fixture_path = "#{::Rails.root}/spec/fixtures"



config.use_transactional_fixtures = false



config.infer_spec_type_from_file_location!



# Filter lines from Rails gems in backtraces.

config.filter_rails_from_backtrace!

config.include Rails.application.routes.url_helpers

config.include Sorcery::TestHelpers::Rails::Controller, type: :controller

config.include Sorcery::TestHelpers::Rails::Integration, type: :feature







config.before(:suite) do

DatabaseCleaner.clean_with(:truncation)

end



config.before(:each) do

DatabaseCleaner.strategy = :truncation

end



config.before(:each, :js => true) do

DatabaseCleaner.strategy = :truncation

end



config.before(:each) do

DatabaseCleaner.start

end



config.after(:each) do

DatabaseCleaner.clean

end





Shoulda::Matchers.configure do |config|

config.integrate do |with|

with.test_framework :rspec

with.library :rails

end

end



end

Solution

  • The problem with your factory is that property values are evaluated just once, at file load time. And then they're reused for all objects.

    thumbnail_image ActiveStorage::Blob.create_after_upload!(...).signed_id
    

    Use a block here

    thumbnail_image { ActiveStorage::Blob.create_after_upload!(...).signed_id }
    

    This way, for each new fabricated object you'll get its own blob.