I am attempting to cache a class variable like so:
Rails.cache.write("##page_types", ##page_types)
This method is called within a class I have called PageTypes.
If I start up a rails console and do:
Rails.cache.write("##page_types", nil)
Rails.cache.read("##page_types")
I get nil. I leave the console open and do this in another window:
rake test:units
When the tests are over, I switch back to my rails console window and do
Rails.cache.read("##page_types")
It returns an array of my test page types! I'm positive they are from my test db because the models all have super high IDs, while my dev data all has very low ones.
I suppose I could append Rails.env to the cache keys, but it seems like the two caches shouldn't be mixing....
Define a different cache backend for your test environment. A memory_store should be perfect for unit tests.
ActionController::Base.cache_store = :memory_store
in config/environments/test.rb:
config.cache_store = :memory_store
Related
My legacy code is using DatabaseCleaner which wipes out database after each test being done. However it also wipes out loaded fixtures data and causes some tests which are using fixtures to fail, something like:
ActiveRecord::RecordNotFound Exception: Couldn't find Country with 'id'=593363170
To make them work together, how can I rewrite all fixtures back to database during test? (I mean not rake tasks)
Solution:
Set self.use_transactional_fixtures = false
at the beginning of the file before which you want to reload fixtures.
Or use use_transactional_tests in Rails 5.
Do not set it in spec_helper as it applies globally so conflicts with DatabaseCleaner.
For an AR query like this:
#users = User.find(some_conditions_here)
then #users is an AR array and I want to cache this.
If I do, in one controller call, a
Rails.cache.write('foo',#users)
it doesn't complain or error out and I can even see a 'foo' under /tmp/cache with a non-zero size but a subsequent controller call to
Rails.cache.read('foo')
returns a nil. When I do both the write and read from a Rails console, it works as expected. What is it about doing it via a controller that causes this problem?
This used to work before in Rails 2... what am I missing?
Check that config.action_controller.perform_caching is set to true.
To quote the Rails caching guide,
caching is disabled by default for development and test, and enabled for production
With Ruby on Rails, is there a way for me to dump my production database into a form that the test part of Rails can access?
I'm thinking either a way to turn the production database into fixtures, or else a way to migrate data from the production database into the test database that will not get routinely cleared out by Rails.
I'd like to use this data for a variety of tests, but foremost in my mind is using real data with the performance tests, so that I can get a realistic understanding of load times.
You can also check out http://github.com/napcs/lazy_developer which will allow you to put the production data into yaml files.
We just had a similar problem and ended up writing a helper method in rspec that fetches some data (in our case, login details for some accounts) from the production database.
The following should give an idea:
require 'yaml'
def accounts
#accounts ||= lambda {
config = YAML.load_file("#{Rails.root}/config/database.yml")['production']
dbh = Mysql.real_connect(config['host'], config['username'], config['password'], config['database'])
accounts = []
result = dbh.query("SELECT `accounts`.* FROM `accounts`")
while row = result.fetch_hash do
row.delete("id")
accounts << Account.make(row)
end
dbh.close
return accounts
}.call
end
You can use the seed.rb inside the db folder, populate your test database with the data you need. There is nice example available on Railscasts: http://railscasts.com/episodes?search=seed
Would recommend you though to keep your production data away from your testing environments. And do make backups!!!
I know that in rails 2.3.2 ActiveRecord queries are cached, i.e. you may see something in the development/production log:
CACHE (0.0ms) SELECT * FROM `users` WHERE `users`.`id` = 1
I was wondering if the same principles apply to rake tasks.
I have a rake task that will query a lot of different models, and I want to know if I should implement my own caching, or if this behavior is included by default.
Also, is there a way to see the sql queries that are performed during the rake task? Similar to that of the development/production log
The SQL cache isn't enabled per default for rake tasks. You can wrap your code in a cache block, like this:
task :foobar => :environment do
ActiveRecord::Base.connection.cache do
User.find 1 # Will hit the db
User.find 1 # Will hit the cache
end
end
This is essentially what Rails does for controller actions. Note that the cache uses memory and rake tasks has a tendency to work with large sets of data, which might give you issues. You can selectively opt-out of caching for parts of your code, using uncached
You are talking about ActiveRecord Query Caching. That should work in Rake-Tasks too, provided you're running them in an environment with caching enabled, e.g. production.
See Rails Guide on Caching for examples.
It may or may not be the right sort of caching for your case:
u1=User.find 1 # loads user1 first time from DB
u2=User.find 2 # loads user2 first time from DB
u1again = User.find 1 # loads user1 from cache
all = User.all # loads user1 and user2 from DB again
A rake task will run in the the environment you specify, in which case it will adopt the rules of that environment.
You can set the rails env from the command line:
RAILS_ENV=test
Logging can be set as part of rake and you should see this in your normal Rails log.
In a Rails application, I need a table in my database to contain constant data.
This table content is not intended to change for the moment but I do not want to put the content in the code, to be able to change it whenever needed.
I tried filling this table in the migration that created it, but this does not seem to work with the test environment and breaks my unit tests. In test environment, my model is never able to return any value while it is ok in my development environment.
Is there a way to fill that database correctly even in test environment ? Is there another way of handling these kind of data that should not be in code ?
edit
Thanks all for your answers and especially Vlad R for explaining the problem.
I now understand why my data are not loaded in test. This is because the test environment uses the db:load rake command which directly loads the schema instead of running the migrations. Having put my values in the migration only and not in the schema, these values are not loaded for test.
What you are probably observing is that the test framework is not running the migrations (db:migrate), but loading db/schema.rb directly (db:load) instead.
You have two options:
continue to use the migration for production and development; for the test environment, add your constant data to the corresponding yml files in db/fixtures
leave the existing db/fixtures files untouched, and create another set of yml files (containing the constant data) in the same vein as db/fixtures, but usable by both test and production/development environments when doing a rake db:load schema initialization
To cover those scenarios that use db:load (instead of db:migrate - e.g. test, bringing up a new database on a new development machine using the faster db:load instead of db:migrate, etc.) is create a drop-in rakefile in RAILS_APP/lib/tasks to augment the db:load task by loading your constant intialization data from "seed" yml files (one for each model) into the database.
Use the db:seed rake task as an example. Put your seed data in db/seeds/.yml
#the command is: rake:db:load
namespace :db do
desc 'Initialize data from YAML.'
task :load => :environment do
require 'active_record/fixtures'
Dir.glob(RAILS_ROOT + '/db/seeds/*.yml').each do |file|
Fixtures.create_fixtures('db/seeds', File.basename(file, '.*'))
end
end
end
To cover the incremental scenarios (db:migrate), define one migration that does the same thing as the task defined above.
If your seed data ever changes, you will need to add another migration to remove the old seed data and load the new one instead, which may be non-trivial in case of foreign-key dependencies etc.
Take a look at my article on loading seed data.
There's a number of ways to do this. I like a rake task called db:populate which lets you specify your fixed data in normal ActiveRecord create statements. For getting the data into tests, I've just be loading this populate file in my test_helper. However, I think I am going to switch to a test database that already has the seed data populated.
There's also plugin called SeedFu that helps with this problem.
Whatever you do, I recommend against using fixtures for this, because they don't validate your data, so it's very easy to create invalid records.