How to make db:test:purge only drop a schema on postresql? - ruby-on-rails

I'm using postgresql on a rails 3 app. I've been using sqlite3 for test environment, but decided to finally switch to the same db I use in production for testing purposes. Problem is, I'm only creating one database and diverse schemas for each environment. This is somethiing I can't change, since the environment is enterprise-constrained.
Hence, I have a test schema. I rund db:schema:load on it and it works fine. I run rake spec on it (I'm using rspec) and it breaks, exactly on the 'db:test:purge' task which comes from rails. Now, this task drops the database. Not only is the database owner different from the schema owner in my case, I'd rather have the task recreate the schema instead of recreating the database.
How can I do this?

Actually there is no real solution for this problem, since rails by default erases the database. It expects this database not to be shared with production (and they might have a point). Nevertheless, I found some interesting links and the way is to patch the rake task. Following the patch and links:
namespace :db do
namespace :test do
task :purge do
ActiveRecord::Migration.verbose = false
Rake::Task["db:schema:load"].invoke
end
end
end
https://github.com/rails/rails/issues/12117#issuecomment-25961999
Run Rails Tests without Dropping Test Database
http://www.pervasivecode.com/blog/2007/09/22/making-rails-raketest-not-drop-your-pgsql-database/

This is not a direct answer to your question, but you can use rspec command instead of rake spec. rspec command doesn't purge your database.

Related

How to stop rspec from dropping the test database before tests

I have two Rails apps that use the same database. One app is managing the database through migrations but the other is just accessing it.
For some reason when I run tests with RSpec in the app that is not managing the database it drops the database before running the tests. But because this app does not know how to recreate the database all tests will fail.
How can I tell RSpec not to drop the database, just use it as it is?
If you don't need to migrate the database you can redefine rspecs-rails
spec:prepare task like this:
lib/tasks/patch_rspec_rails.rb
Rake::Task["spec:prepare"].clear
namespace :spec do
task :prepare do
ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
end
end
The original spec:prepare task callstest:prepare, which setups the db.
The task test:prepare exists since Rails 4.0 (or maybe earlier). This task also exists within Rails 5.0. It is a hook for railsties to add test dependent setups. You can check its definition with rake -W test:prepare. That
the task is hit you can check with rake --trace spec.
ActiveRecord uses this task to check the migration state and setup the db.
When this task is not called, no db will be dropped or created.
But be aware, when some other gem uses test:prepare as a hook too plug into tests, it will not work.
Edit:
Since Rails 4.1 you can set config.active_record.maintain_test_schema = false within config/environments/test.rb. This way Rails should no longer try to migrate your test schema.
Ideally RSpec should be reinitialisation the database for testing to ensure your environment is in a reliably, predictable state.
What you could do is for the Rails app that isn't managing the database carry out a rake db:schema:dump to generate the schema.rb which will then be used by RSpec - of course make sure that your database.yml test configuration isn't pointing to your live database.
I know that this isn't technically a solution to your question but it should prevent the underlying issue which is causing your tests to fail.

rake db:migrate doesn't generate table in postgresql

I've been having a problem which doesn't seem uncommon (I've read a lot of stack overflow pages in the last 2 days) but every solution I've read hasn't worked for me.
I've been following this video tutorial
At 6:42 the tutor shows the tables in postgresql and mine don't show up.
When I try rake db:migrate the files migrate no problem. rake doesn't throw up any errors, the relevant .rb files are created in the models folder, my schema.rb looks right. It seems postgresql just isn't reading my schema file.
My problem sounds identical to
rake db:migrate doesn't seem to work in production
However typing rake db:migrate RAILS_ENV=production doesn't work. (I've tried this a few times after other rake commands like rake db:rollback STEP=3 in the past few days because I was paranoid it was the solution, this person on ruby forum, has the same problem and is offered the same answer).
This is my first attempt at programming anything and I'm loving the tutorial (and the learning curve this problem has turned out to be) Asking here is pretty much my last resort because I've tried everything I can understand online as a possible solution so please help me! Thanks a lot in advance
There is quite a bit of confusion going on here:
Migrations
Migrations are a convenient way to alter your database schema over
time in a consistent and easy way. They use a Ruby DSL so that you
don't have to write SQL by hand, allowing your schema and changes to
be database independent.
Postgres does not read your schema file or migrations - rather migrations run SQL queries against your database. In this case a CREATE TABLE ... query will be run when the migration is run.
Migrations are basically a more maintainable and sane way of doing what was classically done by opening a DB console and running SQL queries.
config/schema.rb is not actually used by the database or ActiveRecord - rather its created when you run migrations as a snapshot of what the database schema should look like. Its just a developer convenience. ActiveRecord gets its mappings by querying the database schema.
Migrations and generators
Migrations do not create model files either - those are generators such as:
rails g model Dude abides:boolean
Which creates a CreateDudes migration and a model at app/models/dude.rb.
In fact migrations are just concerned about altering the DB schema and don't care if the model file exists or not - the models is not actually used until you query the database for records.
ENV vars
RAILS_ENV=production sets a environmental variable.
rake db:migrate RAILS_ENV=test
Is the documented way to run a migration in a different environment. Some obscure shells require the ENV var to prefix the command.
However - if you are running a production server you should set the RAILS_ENV env var permanently - not on invocation! This prevents embarrassing misstakes when someone expected you to have configured the server properly and just ran rails s when restarting the server. See the documentation for your server OS on how to set env vars.
If you are still running the migration and do not see the expected results you most likely have not configured config/database.yml properly - the migrations are running. But not against the database you would expect.
http://guides.rubyonrails.org/active_record_migrations.html

Which one does rspec run first? spec_helper.rb or db:test:prepare

I'm trying to implement an additional check for faulty database.yml configurations. In our configuration, we follow the rails database.yml convention, which is basically adding "_#{env}" suffix to the names of the databases. We've had an incident on another project (not rails), where someone forgot to switch databases before running unit tests, causing us to lose data on the staging environment. We hacked a workaround by adding a simple check, which is: if the database name doesn't end with "_test", don't wipe it, don't run unit tests on it.
So what is the right way of implementing this check for rails. I figured I can do it in the spec_helper.rb, but when I ran the tests after I changed the database name, instead of raising the error message that I wrote, it threw:
TinyTds::Error: Database 'some_db_name' does not exist. Make sure that the name is entered correctly.
Which means, it connected to the db before spec_helper.rb is loaded. I couldn't find any information on when the db:test:prepare is executed, and didn't ahve the courage to test it with an existing db that doesn't have "_test" suffix.
Is there a hook that I can use for this?
Including in your spec_helper.rb
ENV["RAILS_ENV"] = 'test'
line the rspec test should run in test environment looking for test database connection string and therefore run always in test database. Without any problem for others differents environment databases

Rake in Rails: should I be using db:reset?

I'm a little confused by the intended use of the default Rails Rake tasks, and would like advice on whether I should be using db:reset or writing a custom Rake task. Nothing clever, just daily housekeeping, and I may well be missing an obvious doc as I'm new to Rails.
My problem: I want to throw away my database and run from a completely clean setup, in order that I can be sure the database contains known data only. This is useful for demo prep, for debugging, and for making sure Jenkins is comparing like-with-like in tests.
Currently, I'm writing this:
bin/rake db:drop:all db:create:all db:migrate db:seed db:test:prepare
This is a lot to type, but leaves seed data only in both dev and test databases. I am unsure how this differs from db:reset, which would be more convenient to type.
Should I use db:reset or write a custom db:from_scratch task?
You should be using:
rake db:reset
This will drop the database, recreate it and load the current schema into it.
For a full list of rake db tasks:
rake --describe db
If your requirements change then it would be better to write a custom rake task, where you can apply your own customisation.
If you're not sure what a rake task does, then I would suggest not using it. In this case, you're probably ok, however db:reset is not the equivalent to what you are doing above. db:reset recreates the database from scheme.rb, this may be different as you could have written migrations that have not yet been run.
I would suggest that you use a custom rake task, you can then modify it to fit your exact purposes, especially if you want to perform other tasks as well (for example tagging in git)
What you are trying to achieve in your the tasks you are running through rake is setting both the test and the development databases. rake db:reset will just do it for your current environment db according to the schema.rb and then load the seeds data into the db. The schema.rb in general is never edited, its for a know-only/refer-only purpose, however some people do tend have different schema.rb which might create a problem :(. What sounds better to me is if you need to set both your development and test database, then run your migrations for the dev environment and use the schema.rb to create the test environment db. I would definitely suggest you to get a second opinion from some Rails guru though to find out a real perfect way to achieve what you want.
rake db:reset
This will drop the database, recreate it and load the current schema into it.
rake db:reset will run rake db:seed
Example :
if you have seed file that you wrote after you ran your migration , it will run that too.

Rails 3 Rake Clone Database for Testing Environment

Is there a rake command in Rails 3 to clone my development database data? I noticed rake db:test:prepare and rake db:test:clone are mentioned throughout various blogs, but running them seems to do nothing. Furthermore, rake -T shows no db:test cases. I've resorted to loading a sql dump for now, but it would be great if I could just clone my existing development data for up-to-date testing.
EDIT --
I desire to test on a database since I am dealing with legacy data that I run through model filters when accessed. Factories won't work for me in this context, since data passed through create is defined as a different schema than that of the legacy data.
rake db:test:prepare is still there even though it doesn't show up in rake -Tdb. I guess the Rails team decided to de-clutter the rake -T output?
I would suggest you not clone your development database but rather rely on factories to give you predictable data you can craft for your exact test cases. Sooner or later, relying on having reliable test data in a database you can access will break your tests. It will also break the tests of anyone else who works on the project. And changes/additions to the data will not propagate to other developers as would your carefully constructed factories.
Look over Machinist, FixJour, FactoryGirl and the lot. They really solve the test data problem well and you check them into version control so the rest of your team has access to them.

Resources