ALTER SEQUENCE on rake db:reset db:migrate not working - ruby-on-rails

I'm developing an information system in Ruby on Rails.
I want to hand out following uids to users:
0: root
1-499: system services (server-side)
500: system admin
501-999: external apps (apps that connect through API)
1000+: human users
I have the following migration set up:
class SetUsersAutoincrementValue < ActiveRecord::Migration
def change
execute("ALTER SEQUENCE users_id_seq RESTART WITH 1000")
end
end
The migration works as expected. However, it doesn't if triggered by rake db:reset db:migrate.
What to do?
Thanks

I suppose rake db:migrate:reset.

Try to restart the ruby server (Puma) may help.
I run the SQL command ALTER TABLE directly on DB to change a table id column from INT to BIGINT.
After updating, when inserting big number I got an error out of range for ActiveModel::Type::Integer with limit 4"
After restart ruby server, everything works well.

Related

Rewriting migration and db:reset

I created an integer for a phone number, and then learned that it is better to consider it as a string due to it's size.
I decided then to change directly the migration and apply db:reset instead of adding a new migration since the project is only on my computer at this moment. Db:reset worked but it doesn't seem that my database changed.
It raised a lot of questions :
Is there a command to analyse a database and identify the types of its columns ?
Does db:reset allow to modify a migration, like after rolling back a migration ?
Even though it isn't preferable, what are the conditions to modify directly a migration ?
The db:reset task resets the database by dropping the database and then loading schema.rb - it does not run migrations again. If you dropped the database, then created it and ran db:migrate then you should get the desired outcome
Change the field as string in migration, then run the commands:-
rake db:drop
rake db:create
rake db:migrate
And it will change the field type from integer to string.

ActiveRecord how to ignore pending migrations

The problem is the following:
I have db/seed.rb full of initial data.
One of migrations depends on data this seed provides.
I'm trying to deploy my app from empty db.
Result is:
RAILS_ENV=production rake db:migrate - fails due to lack of initial data
RAILS_ENV=production rake db:seed - fails due to pending migrations
I wanted to somehow tell rake to ignore pending migrations, but unable to do it so far.
UPDATE (due to additional experience)
Sometimes migrations and model code goes out of sync, so migrations are not being run.
To avoid this problem recently used redefining of model in migrations:
# reset all callbacks, hooks, etc for this model
class MyAwesomeModel < ActiveRecord::Base
end
class DoSomethingCool < ActiveRecord::Migration
def change
...
end
end
I am not very sure if this will help you. But I was looking for something and found this question. So it looks like this might help:
In RAILS_ROOT/config/environments/development.rb
Set the following setting to false:
# NOTE: original version is `:page_load`
config.active_record.migration_error = false
In my situation it now does not show the pending migration error anymore. Should work for rake tasks and console for the same environment as well.
Source in rails/rails
Rename the migration dependent on the data from:
20140730091353_migration_name.rb
to
.20140730091353_migration_name.rb
(add a dot at the start of the filename)
Then run rake db:seed (it will no longer complain on the pending migrations) and then rename back the migration.
If you have more migrations following after, you have to rename all of them or just move it temporary away.
Rails stores migration information in a table called schema_migrations.
You can add the version from your migration into that table to skip a specific migration.
The version is the number string which comes before the description in the file name.
[version]_Create_Awesome.rb
I had a similar issue. I commented out the add_column lines and ran the rake db:migrate commands and then removed the comment when I will need it for the testing or production environment.
There is no way unless you monkey patch the Rails code. I strongly advise you to fix your migrations instead.
A migration should not depend on the existence of some data in the database. It can depend on a previous migration, but of course absolutely not on the data on the db.
If you came across the "pending migrations" issue when trying to seed your data from within a running Rails application, you can simply call this directly which avoids the abort_if_pending_migrations check:
ActiveRecord::Tasks::DatabaseTasks.load_seed
See where seeds are actually called from within ActiveRecord:
https://github.com/rails/rails/blob/v6.0.3.2/activerecord/lib/active_record/railties/databases.rake#L331
and see the DatabaseTasks docs:
https://apidock.com/rails/v6.0.0/ActiveRecord/Tasks/DatabaseTasks
https://apidock.com/rails/v6.0.0/ActiveRecord/Tasks/DatabaseTasks/load_seed

How to keep overview of the migrations?

I have a question regarding my migrations in rails.
Normally when i want to add a colum to a model for i dont make extra migrations but instead i perform this steps:
rake db:rollback
next i change the migration file in db/migrations and rerune:
rake db:migrate
The biggest problem is that when i do this i loose my data.
Previous i wrote migrations from the command line with for example
rake g migration Add_Column_House_to_Users house:string
The problem with this approach is that my db/migrations folder afterwards get very large and not very clear! I mean at the end i dont know wich variables the object has! Im not an expert in rails and would like to ask you how to keep the overview over the migrations!Thanks
Just a minor thought - I just use the file db/migrate/schema.rb to determine whats in the database as opposed to tracking through the migrations
You definitely shouldn't use db:rollback with a table with existing data.
I have a few production RonR apps with a ton of data and there are 100+ entries in the migrations table and adding new migrations to tweak tables is the rails way to do things. Not sure what you mean by lucid, but your schema and data model are going to change over time and that is ok and expected.
One tip. The migrations are great, but they are just the beginning, you can include complex logic as needed to fix your existing data (like so)
Changing data in existing table:
def up
add_column :rsvps, :column_name_id, :integer
update_data
end
def update_data
rsvps = Rsvp.where("other_column is not null")
rsvps.each do |rsvp|
invite = Blah.find(rsvp.example_id)
...
rsvp.save
end
end
Another tip: backup your production database often (should do this anyway), but use it to test all of your migrations before deploying. I run scripts like this all the time for local testing:
mysql -u root -ppassword
drop database mydatabase_dev;
create database mydatabase_dev;
use mydatabase_dev;
source /var/www/bak/mydatabase_backup_2013-10-04-16.28.06.sql
exit
rake db:migrate

Can I delete a migration file?

When I ran bundle exec rake db:test:prepare I got the following:
rake aborted!
Multiple migrations have the name CreateMicroposts
To check the status of my migration files, I ran
rake db:migrate:status
And got:
Status Migration ID Migration Name
------- --------------- -----------------
up 20120616205407 Create users
up 20120622103932 Add index to users email
up 20120622114559 Add password digest to users
up 20120628095820 Add remember token to users
up 20120704123654 Add admin to users
down 20120706103254 Create microposts
up 20120707073410 Create microposts
As you can see, I have two migration files with the exact same names and the exact same code in them. It's only their statuses differ, i.e. Up and Down.
What does Up and Down signify?
And which one can I delete, if I have to?
The problem is that you have two different migration files containing the header
class CreateMicroposts< ActiveRecord::Migration
rake db:migrate:status does not check the status of your migration files. It tells you what migrations will be applied if you run rake db:migrate. The up/down labels are pretty much self-explanatory: it tells you whether the migration will be applied via the up method or the down method. The up method is ran when you migrate and the down when you rollback a migration. You can make some further reading about Rails migrations here.
up is the method called when "evolving" (ie migrating to a new schema), while down is the method called when "regressing" (ie migrating to an older schema version, because one of your changes doesn't suit you). db:migrate calls up, db:rollback calls down. In recent versions of rails, there's change that handles both at the same time.
As for the deletion... I don't do activerecord much these days, but I think you're free to do whatever you want with your files. I don't think deleting a duplicate file will do any harm, and if it does.. Well, you use source control, right ? :)

Create Sequence In Migration Not Reflected In Schema

I have an application that requires a sequence to be present in the database. I have a migration that does the following:
class CreateSequence < ActiveRecord::Migration
def self.up
execute "CREATE SEQUENCE sequence"
end
def self.down
execute "DROP SEQUENCE sequence"
end
end
This does not modify the schema.rb and thus breaks rake db:setup. How can I force the schema to include the sequence?
Note: The sequence exists after running rake db:migrate.
Rails Migrations because they aim toward a schema of tables and fields, instead of a complete database representation including stored procedures, functions, seed data.
When you run rake db:setup, this will create the db, load the schema and then load the seed data.
A few solutions for you to consider:
Choice 1: create your own rake task that does these migrations independent of the Rails Migration up/down. Rails Migrations are just normal classes, and you can make use of them however you like. For example:
rake db:create_sequence
Choice 2: run your specific migration after you load the schema like this:
rake db:setup
rake db:migrate:up VERSION=20080906120000
Choice 3: create your sequence as seed data, because it's essentially providing data (rather than altering the schema).
db/seeds.rb
Choice 4 and my personal preference: run the migrations up to a known good point, including your sequence, and save that blank database. Change rake db:setup to clone that blank database. This is a bit trickier and it sacrifices some capabilities - having all migrations be reversible, having migrations work on top of multiple database vendors, etc. In my experience these are fine tradeoffs. For example:
rake db:fresh #=> clones the blank database, which you store in version control
All the above suggestions are good. however, I think I found a better solution. basically in your development.rb put
config.active_record.schema_format = :sql
For more info see my answer to this issue -
rake test not copying development postgres db with sequences
Check out the pg_sequencer gem. It manages Pg sequences for you as you wish. The one flaw that I can see right now is that it doesn't play nicely with db/schema.rb -- Rails will generate a CREATE SEQUENCE for your tables with a serial field, and pg_sequencer will also generate a sequence itself. (Working to fix that.)

Resources