In my Rails app, I have a model called Rutinas. After some time, I needed to add some columns to the table so I generated a migration 20171116094810_add_votos_y_veces_asignada_to_rutinas.rb
:
class AddVotosYVecesAsignadaToRutinas < ActiveRecord::Migration[5.1]
def change
add_column :rutinas, :votos_pos, :integer, :default => 0
add_column :rutinas, :votos_neg, :integer, :default => 0
add_column :rutinas, :veces_asig, :integer, :default => 0
end
end
After some other migrations, I needed to delete two columns that I don't need anymore votos_pos
and votos_neg
so I generated another migration 20171117092026_remove_votos_from_rutinas.rb
:
class RemoveVotosFromRutinas < ActiveRecord::Migration[5.1]
def change
remove_column :rutinas, :votos_pos, :integer
remove_column :rutinas, :votos_neg, :integer
end
end
The problem is that when I run rails db:migrate
to migrate this last migration, it throws some weird error:
== 20171117092026 RemoveVotosFromRutinas: migrating ===========================
-- remove_column(:rutinas, :votos_pos)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "rutinas"
C:/Users/pepe/Dropbox/pepe/KeepMeFit/KeepMeFit-git/db/migrate/20171117092026_remove_votos_from_rutinas.rb:3:in `change'
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Caused by:
ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "rutinas"
C:/Users/pepe/Dropbox/pepe/KeepMeFit/KeepMeFit-git/db/migrate/20171117092026_remove_votos_from_rutinas.rb:3:in `change'
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Caused by:
SQLite3::ConstraintException: FOREIGN KEY constraint failed
C:/Users/pepe/Dropbox/pepe/KeepMeFit/KeepMeFit-git/db/migrate/20171117092026_remove_votos_from_rutinas.rb:3:in `change'
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
My Rutinas model is the following:
class Rutina < ActiveRecord::Base
validates_presence_of :nombre
belongs_to :user
has_many :repeticions
has_many :entrenos, dependent: :destroy
has_many :votos
has_many :days, dependent: :destroy
def get_array_dias
(1..self.repeticions.last.dia).to_a
end
def get_number_of_days
days.count
end
end
User, repeticion, entreno, voto and day are other tables which are non-related to the columns that I'm trying to delete. That is to say, these columns are not a foreign key and any foreign key references these columns.
It will be fixed in Rails 6 including https://github.com/rails/rails/pull/32865 . This requires SQLite database 3.8 and higher. I do not think it will be back ported into Rails 5.2 or older.
My answer may not give you any practical feedback how to write your code, what I can say now is upgrading Rails 6 (release date is not fixed) may resolve this problem.
It seems like the problem is the limitation of SQLite. If you check the documentation you'll see, that it only allows adding a column, but not removing one: https://sqlite.org/lang_altertable.html
It is possible, that the migration actually drops the whole table and recreates it, when a column is removed. This would explain the
DROP TABLE "rutinas"
message. Of course if the while table is dropped, it would make sense that certain foreign key constraints fail.