Dependency on fixture data in rails initializer - ruby-on-rails

I have an initializer which sets a default that is used throughout the app. The value is an ActiveRecord model, I'm essentially caching it for the lifetime of the app:
##default_region = Region.find_by_uri("whistler")
The record is guaranteed to be in the database: it's fixture data which is referenced by other models. This works fine, except in the test environment where the database is purged before every test run. (I'm running on edge rails and I think that's recent behavior: I used to be able to insert the data manually and keep it between test runs.) I also have the record in my regions.yml fixture file, but fixtures aren't loaded until after the rails initializer is done.
What's the right way to deal with such a dependency on fixture data? Or is there a better way to structure this? I'd rather not use a before_filter because there's no sense reloading this on each request: it will not change except on a different deployment.

I'd put something like this in region.rb:
def self.default_region
##default_region ||= Region.find_by_uri("whistler")
end
Then you can access it as Region.default_region wherever you need it, and it's only looked up once - the first time it's called - and by then the fixtures will be in place.

Not really familiar with Ruby or Rails... but why don't you try a "lazy-loading" scenario? Basically, have a global function that would check to see if the data was loaded, and if not, grab it from the database, then cache it. And if it was already cached, just return it.
That way, you won't be attempting to hit the database until that function is called for the first time and everything should be initialized by then.

Related

How to use FactoryBot with a read-only database

I have 2 Rails applications. The first one manages user data. The second one has read only access to the first's database to retrieve that user data.
user = FactoryBot.create(:user)
# Test user associations that only exist in the 2nd application
Obviously that line will fail as the user cannot be created due to database-level permissions. My first thought would be to open up the first database's _test database to have full write permissions, but this feels wrong as it would have different permissions than the production environment, potentially hiding/causing other issues.
What is the best approach for using FactoryBot to test aspects of the second application using mock user data from the first?
Update
One thought I had was to pre-load a dummy test database with data and ensure the 2nd application has read only access to it. Then my tests would simply query for an existing user (would need to have prior knowledge about the data inside though) instead of using FactoryBot to create ones. Is this a viable approach?
Loading a fixture would be a good choice here as you can simulate the read only database with your user data interactions.
You will need to read in a yml or xml file similar setup to your db .. parse out the mappings of the file and then you can use it.
Quick example:
def fixture_file_path(filename)
Rails.root.join("spec/fixtures/#{filename}").to_s
end
def read_fixture_file(filename)
File.read fixture_file_path(filename)
end
let(:fixture) { read_fixture_file("file.xml") }
Then create a subject here which will be useful as you will be calling this in many tests .. call the fixture
subject(:service) { described_class.call fixture }
Then you can go from there and build the interactivity to test how you need.

Overriding create method in rspec

I'm trying to write specs for a method that uses the #create method which writes to the database which is causing issues because its being created with an object that's not saved to the database -- does anyone know how to override #create so it doesn't try to save to the database when running specs?
I get this error:
ActiveRecord::RecordNotSaved:
You cannot call create unless the parent is saved
As #Raghu pointed out, you need mocking/stubbing (see http://blog.firsthand.ca/2011/12/example-using-rspec-double-mock-and.html) to avoid actually running the create method. You probably don't want to test if create actually works. You are more likely testing that create is called on right time, on right model and with right options.
This is the place to use a Stub / Double (formerly, and still commonly, known as "Mocks")

About my way to truncate tables in my test DB

In my Rails app development, When I run my Rspec test, I need to truncate all tables in my test database in after(:all) .
(That's to clean up all data in every table in test db)
To approach this, I am thinking to first get all ActiveRecord models which represent the tables in test db, then for each model, I use delete_all method to clean up each table. Thant's something like:
ALL_ACTIVE_RECORD_MODELS.each do |model|
model.delete_all
end
I have two questions to ask regards to this:
1. How to get all active record models in Rails in my rspec code?
2. Am I using a acceptable way to truncate all tables in my test DB or not? If not, what is the alternative way?
There is a gem to do exactly this task called database_cleaner: https://github.com/bmabey/database_cleaner.
It will make sure that everything is removed from your database however its default strategy is not to delete content but to use transactions and simply roll back the changes after each test.
Be warned that this can occasionally lead to a gotcha when testing behaviour that's intended to be transactional as you won't see your transaction execute. You can fix this by adding self.use_transactional_fixtures = false before any set of tests that you don't want to use transactions. Remember to clear your data away again afterward though.

In rails 3, how can I ensure enum tables are loaded into the test database before models load?

Using ActiveSupport::TestCase. I think that's the old Test::Unit.
I have several tables that represent enumerated values. These never change and I would like to use their data in class scope for activerecord finders.
This causes a problem with tests because model classes load before fixtures and fixtures are rolled back between tests. I can't copy the enum tables into a fixture because the data will not yet be loaded when models load.
Is there a way to bring the test database to an initial state before models load and before the fixture transaction begins?
How about defining a setup method for your tests?
Or seeding the database using db/seeds.rb?
If they never ever change you could put the create statements directly into your migrations so they are created when the tables are rebuilt - seems a bit messy to be honest though but should work.

Rails test fixtures vs uniqueness

In Rails, fixtures records seem to be inserted & deleted in isolation for a given model. I'd like to test having many objects/rows in one transaction, eg. to check uniqueness. How to do it?
Fixtures are not validated. When you set them up they can be totally wrong and Rails won't complain until something blows up. It's a good idea to make sure your initial test DB (that is seeded with your fixtures) is in a valid state before tests are run.
For checking things like uniqueness, I would create the records on the fly and not rely on fixtures. Either create them right in your test case, or use something like FactoryGirl (which by the way, is a great way to clean up your tests and stop using fixtures completely).
Are you saying you want to build a test to check the rails "validates_uniqueness_of" operator or that you want to test the logic of your own unique record? In the first case, I wouldn't bother, the Rails tests cover that. In the second case, I would create a test that creates a record that is the same as one in the fixtures.
In the broader sense of putting multiple saves into a single transaction, you can create your objects and then:
MyModel.transaction do
model1.save
model2.save
end
but I don't think this is the way to accomplish either of the things it seems that you want to do.

Resources