Migration with SQL sequence is not applied in test environment - ruby-on-rails

I have the current migration
class CreateSlugSequence < ActiveRecord::Migration[5.2]
def up
execute <<-SQL
CREATE SEQUENCE slug_sequence
SQL
end
def down
execute <<-SQL
DROP SEQUENCE slug_sequence
SQL
end
end
I run rails db:migrate
Enter rails c (development mode)
Run ActiveRecord::Base.connection.exec_query("select nextval('slug_sequence')")[0]['nextval']
And get the expected value
But if I enter rails c in test mode, for some reason, the sequence table does not exist
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: relation "slug_sequence" does not exist
I ran ActiveRecord::Migrator.current_version, to check what was the last migration applied and it returns the latest version.
Thanks for the help in advance.

I recommended dropping the test db and recreating it. Although these should remain in sync they sometimes do not and you have to do manual steps to get them together.
RAILS_ENV=test rake db:reset
Weird that it is not working with that, would be interesting to drop a pry debugger in that task and see what is going on. https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/databases.rake#L122
Manual steps
RAILS_ENV=test rake db:drop
RAILS_ENV=test rake db:create
RAILS_ENV=test rake db:migrate

I found the way to fix rails db:reset command, you just need to add line config.active_record.schema_format = :sql in your application.rb so info about sequence will be stored in structure.sql. Please take a look that with default schema dump :ruby info about seqeunce is not stored in schema.rb file.
Important: make sure to firstly create structure.sql with rails db:migrate and then run rails db:reset. After just rails db:migrate I'm still getting the error you want to fix.

Related

Migration not executed from rspec

I created the following migration script (using bundle exec rails generate migration CreateSequenceStudentId):
class CreateSequenceStudentId < ActiveRecord::Migration[6.0]
def change
# Based on: https://schmijos.medium.com/execute-sql-in-rails-migrations-cdb26f51c683
execute 'CREATE SEQUENCE IF NOT EXISTS student_id;'
end
end
Then executed bundle exec rails db:migrate RAILS_ENV=test and it completed. I can access the sequence using psql student_test -c"select nextval('student_id')". Running psql student_test -c"select * from schema_migrations sm" lists 20201122013457 at the very last. No problems so far.
I then wrote the following spec to access the sequence:
sql = "select nextval('student_id')"
p Student.connection.select_all(sql)
And it failed:
# --- Caused by: ---
# PG::UndefinedTable:
# ERROR: relation "student_id" does not exist
# LINE 1: select nextval('student_id')
And I executed psql student_test -c"select nextval('student_id')" one more time and got:
ERROR: relation "student_id" does not exist
LINE 1: select nextval('student_id')
bundle exec rails db:migrate:status RAILS_ENV=test gives:
Status Migration ID Migration Name
--------------------------------------------------
...
up 20201122013457 Create sequence student
So it indicates the migration executed successfully.
psql student_test -c"select * from schema_migrations sm" gives:
version
----------------
20201122013457
20191209013052
20191220005953
20191225001051
20191225001255
20191225001458
...
The new script was executed first. This smells fishy.
Sounds like the migration ran successfully when using db:migrate but not when running rspec. Appreciate any pointers on what I could be doing wrong.
PS: Based on this solution, I have checked if the script name is unique and it is.
I was able to fix your issue by running exact below commands. I found the answer here.
RAILS_ENV=test rake db:drop
RAILS_ENV=test rake db:create
RAILS_ENV=test rake db:migrate
UPDATE:
I found also the way to fix rails db:reset command, you just need to add line config.active_record.schema_format = :sql in your application.rb so info about sequence will be stored in structure.sql. Please take a look that with default schema dump :ruby info about seqeunce is not stored in schema.rb file.
Important: make sure to firstly create structure.sql with rails db:migrate and then run rails db:reset. After just rails db:migrate I'm still getting the error you want to fix.

Rails: How to delete a pending migration

I'm currently following the ruby on rails tutorial: http://guides.rubyonrails.org/getting_started.html.
I am trying to save data into the database. However, when I run: rails server I get the following error:
Migrations are pending. To resolve this issue, run: bin/rake db:migrate RAILS_ENV=development
I've looked at the other articles and when I run:
bin/rake db:migrate
I get a rake aborted!
After running:
rake db:abort_if_pending_migrations....
I see that:
You have 1 pending migration:
20150805200129 CreateDatabases
SQLite3::SQLException: table "databases" already exists:
and it just tells me to run rake db:migrate to start again.
It seems that it already exists. Is there a way to cancel the pending migration?
Sometimes, even dropping a local development database is not a good idea.
There are better ways to delete/destroy a specific migration in your Rails application.
You could use rails d migration command to destroy a particular migration:
rails d migration MigrationName
To undo the changes corresponding to a particular migration, you can use db:migrate:down method like this:
rake db:migrate:down VERSION=XXX
Sometimes, things could get more messy and in those situation another handy thing is to take a look at the schema_migrations table in your database which has all the migrations with their version saved in it.
You can delete a particular migration from this table like this:
delete from schema_migrations WHERE version = VERSION;
if you don't want that migration to be present anymore.
Your migration may have failed midway (so it created the table, but didn't finish).
You are just using development environment, so it's okay to just drop the database and rebuild it from scratch:
rake db:drop # THIS WILL DELETE YOUR DATABASE
rake db:create
rake db:migrate
If you are like me and maintain your database structure outside of Rails, you can just delete the migration file from db/migration. I got the error in the OP's question when I used the rails generate command to create a model class, forgetting that it also creates a migration file.
Do not use this method if you rely on Rails to maintain your database structure!
I keep my Rails structure file up to date by building it from the database using:
bundle exec rake db:structure:dump
I do not encourage to drop the database and start from the beginning especially when you already have the data inside the database.
My approach to this will be migrate first, then rollback. After that you can safely delete the migration file. So the procedure is as following.
rails db:migrate
rails db rollback
rm db/migrate/your_last_migration_file.rb
You can recreate database and run all migrations in your development environment with such command
rails db:migrate:reset
If you want to revert the wrong migrations, You can drop the whole db using this:
rake db:drop
Then remove the migrations file manually(This wont corrupt the db when you recreate as the Schema migrations would be dropped as well).
Then run
rake db:migrate
And if there is data to be seeded, then run this as well
rake db:setup

Rails: I modified my migration file (Bad, I know)

I recently started using Rails, and created a few Models using the CLI which in turn created some migrations.
I ran the rake db:migrate command after adding all my columns in there, and then realized that I'd left out the associations.
So what did I do?
I went ahead and edited the migrations to include those keys.
I ran rake db:migrate again, and nothing changed in the schema.
Then I ran rake db:reset and then rake db:setup.
When that didn't work, I deleted my schema.rb (the darn thing wouldn't get updated!) and tried recreating it. When I realized that didn't work, I dropped the database, and killed the schema.
Now I'm stuck with some manually modified migrations, no schema.rb and no database.
How do I get the modified migrations to generate a schema, and play nice with Rails?
In development it does not matter to drop and rebuild your database. I do it often and I even have a rake task for that. The 3 command to chain are:
rake db:drop
rake db:create
rake db:migrate
# And a 4rth optional command to rebuild your test database
rake db:test:prepare
With this you should be good
Next time you need to modify a migration manually after migrating it, you should process by:
rake db:rollback
edit your migration
rake db:migrate
Following those steps will save you some headaches
Bonus info:
After you deployed your migration to your production server you cannot manually modify it, hence you must write another migration that will perform the modification (adding columns, etc...)

What does rake db:test:prepare actually do?

I am following the rails tutorial videos and I can't figure out what the db:test:prepare command actually does. Can someone provide an explanation?
The rake db:migrate above runs any pending migrations on the
development environment and updates db/schema.rb. The rake
db:test:load recreates the test database from the current
db/schema.rb. On subsequent attempts, it is a good idea to first run
db:test:prepare, as it first checks for pending migrations and warns
you appropriately.
-- http://guides.rubyonrails.org/testing.html
Basically it handles cloning the database so you don't have to run the migrations against test to update the test database.
Specifically, rake db:test:prepare will do the following:
Check for pending migrations and,
load the test schema
That is, it will look your db/schema.rb file to determine if any migrations that exist in your project that have not been run. Assuming there are no outstanding migrations, it will then empty the database and reload it based on the contents of the db/schema.rb file.
rake db:test:prepare is a good solution for PG issues like this.
“PG::UndefinedTable: ERROR: relation does not exist” with a correct Rails naming and convention" where I couldn't just execute rake db:migrate RAILS_ENV=production
When, for example you can't create test database for a bug discussed here: "PG undefinedtable error relation users does not exist"
All arround this error
"PG::UndefinedTable: ERROR: relation xxxxx does not exist”

How to revert all migrations at once in Ruby on Rails 3?

I tried to run:
rake db:migrate VERSION=0
It reverts all migrations except the last one.
Then I tried to run:
rake db:migrate:down VERSION=<timestamp_of_last_migration>
but it didn't revert either. Why ?
Is there a command that runs all down methods at once ?
If your database only related to this project, and you are trying to undo everything in your migrations, I'd simply drop the database, and then run rake db:create.
Then you have an empty database ready to go.
Or is there another reason you're trying to run the down scripts?
You could check this list.
Maybe this could help you
rake db:create[:all]: If :all not specified then create the database defined in config/database.yml for the current RAILS_ENV. If :all is specified then create all of the databases defined in config/database.yml.
rake db:fixtures:load: Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y
rake db:migrate [VERSION=n]: Migrate the database through scripts in db/migrate. Target specific version with VERSION=n
rake db:migrate:redo [STEP=n]: (2.0.2) Revert the database by rolling back "STEP" number of VERSIONS and re-applying migrations.
rake db:migrate:reset: (2.0.2) Drop the database, create it and then re-apply all migrations. The considerations outlined in the note to rake db:create apply.
rake db:reset: Drop and re-create database using db/schema.rb. The considerations outlined in the note to rake db:create apply.
rake db:rollback [STEP=N]: (2.0.2) Revert migration 1 or n STEPs back.
rake db:schema:dump: Create a db/schema.rb file that can be portably used against any DB supported by AR
rake db:schema:load: Load a schema.rb file into the database
rake db:sessions:clear: Clear the sessions table
rake db:sessions:create: Creates a sessions table for use with CGI::Session::ActiveRecordStore
rake db:structure:dump: Dump the database structure to a SQL file
rake db:test:clone: Recreate the test database from the current environment's database schema
rake db:test:clone_structure: Recreate the test databases from the development structure
rake db:test:prepare: Prepare the test database and load the schema
rake db:test:purge: Empty the test database
there is another way:
rake db:rollback STEP=100
this will revert last 100 migrations
taken from http://guides.rubyonrails.org/migrations.html#rolling-back
try:
rake db:migrate:down VERSION=<timestamp_of_first_migration>
this will run the self.down for your first migration, essentially wiping everything out. at least, it just did for me!

Resources