Как вы пропустите неудачные миграции?(грабли дБ: мигрировать) - PullRequest
38 голосов
/ 11 января 2012

Кажется, я не могу найти вариант или что-то, что позволяет мне пропустить миграции.

Я знаю, о чем ты думаешь: «Ты никогда не должен был этого делать ...»

Мне нужно пропустить миграцию, которая вносит изменения в определенные пользовательские записи, которых нет в моей базе данных разработки. Я не хочу менять миграцию, потому что она не является частью источника, с которым я должен работать. Есть ли способ пропустить миграцию или пропустить неудачные миграции?

Заранее спасибо!

Ответы [ 7 ]

58 голосов
/ 11 января 2012

Я думаю, что вы должны исправить ошибочные миграции, чтобы они были менее хрупкими, я бы предположил, что пары if операторов и, возможно, rescue будет достаточно.

Но, если исправить миграциина самом деле это не вариант, вы можете подделать его различными способами.Прежде всего, вы можете просто закомментировать методы миграции, запустить rake db:migrate, а затем раскомментировать (или отменить) ошибочную миграцию.

Вы также можете подделать ее внутри базы данных, но этот вид чиканерства не являетсярекомендуется, если вы не знаете, что делаете, и не возражаете против ручного исправления ошибок, когда вы (неизбежно) совершаете ошибку.В вашей базе данных есть таблица с именем schema_migrations, в которой есть один столбец varchar(255) с именем version;эта таблица используется db:migrate для отслеживания примененных миграций.Все, что вам нужно сделать, это ВСТАВИТЬ соответствующее значение version, и rake db:migrate будет думать, что миграция завершена.Найдите поврежденный файл миграции:

db/migrate/99999999999999_XXXX.rb

, затем перейдите в базу данных и скажите:

insert into schema_migrations (version) values ('99999999999999');

, где 99999999999999, конечно, число из имени файла миграции.Затем запуск rake db:migrate должен пропустить эту миграцию.

Я бы выбрал второй вариант перед третьим, я включаю только параметр "hack schema_versions" для полноты.

16 голосов
/ 14 ноября 2012

У меня была проблема, когда у меня была миграция, чтобы добавить таблицу, которая уже существовала, поэтому в моем случае мне пришлось также пропустить эту миграцию, потому что я получал ошибку

SQLite3::SQLException: table "posts" already exists: CREATE TABLE "posts"

Я просто закомментировал содержимое метода создания таблицы, запустил миграцию и затем раскомментировал ее. Это своего рода ручной способ обойти это, но это сработало. Смотрите ниже:

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
15 голосов
/ 01 августа 2012

Это хороший способ сделать это для разовых ошибок.

db:migrate:up VERSION=my_version

Это запустит одно действие миграции "up". (Существует и обратное, если вам это нужно, просто замените «вверх» на «вниз».) Таким образом, вы можете запустить будущую миграцию, которая заставит работать более старую (которую нужно пропустить), или просто запустить миграция впереди выборочно.

Я также считаю, что вы можете повторить миграцию следующим образом:

rake db:migrate:redo VERSION=my_version

Я не пробовал этот метод лично, поэтому YMMV.

7 голосов
/ 27 июля 2015

Если вам нужно сделать это, миграции вашего приложения перепутались!

Вставляет все отсутствующие миграции:

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) }
1 голос
/ 14 ноября 2012

иногда необходимо заново заполнить schema_migrations таблицу определенно правильными миграциями ... ТОЛЬКО ДЛЯ ЭТОЙ ЦЕЛИ я создал этот метод

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

Вы можете скопировать и вставить его в любую модель и использовать ее из консоли

YourModel.insert_missing_migrations("xxxxxxxxxxxxxx")

(или как-то еще)

где "xxxxxxxxxxxxxx" -это временная метка миграции, перед которой вы хотите остановить вставку (вы можете оставить ее пустой)

!!!используйте его, только если вы абсолютно понимаете, какой результат вы получите !!!

1 голос
/ 11 января 2012

Вместо того, чтобы пропустить миграцию, вы можете сделать миграцию более умной, добавив в нее некоторую IF, чтобы вы могли проверить «определенных пользователей»

0 голосов
/ 24 января 2019

Чтобы пропустить все отложенные миграции, запустите это в своем терминале:

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

(для macOS вместо xclip использовать pbcopy)

Затем CTRL-V результат внутри консоли рельсов:

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)}

И нажмите ENTER.

Вы можете изменить список миграций, которые хотите пропустить, удалив их из массива a перед выполнением строки.

...