可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I can't seem to find an option or anything that allows me to skip migrations.
I know what you're thinking: "you should never have to do that..."
I need to skip a migration that makes changes to specific user records that don't exist in my development database. I don't want to change the migration because it is not part of the source I am supposed to be working with. Is there a way to skip a migration or skip failed migrations?
Thanks in advance!
回答1:
I think you should fix the offending migrations to be less fragile, I'd guess that a couple of if
statements and perhaps a rescue
would be sufficient.
But, if fixing the migrations really isn't an option, you can fake it in various ways. First of all, you could just comment out the migration methods, run rake db:migrate
, and then uncomment (or revert) the offending migration.
You can also fake it inside the database but this sort of chicanery is not recommended unless you know what you're doing and you don't mind manually patching things up when you (inevitably) make a mistake. There is a table in your database called schema_migrations
that has a single varchar(255)
column called version
; this table is used by db:migrate
to keep track of which migrations have been applied. All you need to do is INSERT the appropriate version
value and rake db:migrate
will think that the migration has been done. Find the offending migration file:
db/migrate/99999999999999_XXXX.rb
then go into your database and say:
insert into schema_migrations (version) values ('99999999999999');
where 99999999999999
is, of course, the number from the migration's file name. Then running rake db:migrate
should skip that migration.
I'd go with the second option before the third, I'm only including the "hack schema_versions
" option for completeness.
回答2:
I had an issue where I had a migration to add a table that already existed, so in my case I had to skip this migration as well, because I was getting the error
SQLite3::SQLException: table "posts" already exists: CREATE TABLE "posts"
I simply commented out the content of the create table method, ran the migration, and then uncommented it out. It's kind of a manual way to get around it, but it worked. See below:
class CreatePosts < ActiveRecord::Migration
def change
# create_table :posts do |t|
# t.string :title
# t.text :message
# t.string :attachment
# t.integer :user_id
# t.boolean :comment
# t.integer :phase_id
# t.timestamps
# end
end
end
回答3:
This is a good way to do it for one-off errors.
db:migrate:up VERSION=my_version
This will run one specific migration's "up" actions. (There is also the opposite if you need it, just replace "up" with "down".) So this way you can either run the future migration that makes the older one (that you need to skip) work, or just run each migration ahead of it selectively.
I also believe that you can redo migrations this way:
rake db:migrate:redo VERSION=my_version
I have not tried that method personally, so YMMV.
回答4:
If you have to do that, your app's migrations are messed up!
Inserts all missing migrations:
def insert(xxx)
ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{xxx})") rescue nil
end
files = Dir.glob("db/migrate/*")
files.collect { |f| f.split("/").last.split("_").first }.map { |n| insert(n) }
回答5:
To skip all pending migrations, run this in your terminal:
echo "a = [" $(rails db:migrate:status | grep "down" | grep -o '[0-9]\{1,\}' | tr '\n' ', ') "];def insert(b);ActiveRecord::Base.connection.execute(\"insert into schema_migrations (version) values (#{b})\") rescue nil;end;a.map { |b| insert(b)}" | xclip
(For macOS use pbcopy instead of xclip)
Then CTRL-V the result inside rails console:
a = [ 20180927120600,20180927120700 ];def insert(b);ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{b})") rescue nil;end;a.map { |b| insert(b)}
And hit ENTER.
You can change the list of migrations you want to skip by removing them from array a before executing the line.
回答6:
Instead of skip the migration you could make your migration smart, adding some IF to it, so you can check "specific users"
回答7:
sometimes, it is necessary to re-fill schema_migrations
table with definitely correct migrations...
ONLY FOR THIS PURPOSE i have created this method
def self.insert_missing_migrations(stop_migration=nil)
files = Dir.glob("db/migrate/*")
timestamps = files.collect{|f| f.split("/").last.split("_").first}
only_n_first_migrations = timestamps.split(stop_migration).first
only_n_first_migrations.each do |version|
sql = "insert into `schema_migrations` (`version`) values (#{version})"
ActiveRecord::Base.connection.execute(sql) rescue nil
end
end
you can copy-paste it into any model you want and use it from console
YourModel.insert_missing_migrations("xxxxxxxxxxxxxx")
(or somehow else)
where "xxxxxxxxxxxxxx"
- is timestamp of migration before which you want to stop insertion (you can leave it empty)
!!! use it only if you absolutely understand what result will you get !!!