Подтвердить что ты не робот

Как распознать направление миграции (вверх или вниз) с миграциями стиля Rails 3 (def change)?

Мне очень нравятся миграции стиля Rails 3, т.е. один метод change достаточно интеллектуальный, чтобы узнать, установлены ли миграции или откат, поэтому мне не нужно писать up и down методы зеркалирования друг друга. Но у меня есть ситуация, когда мне нужно пропустить некоторый код при откат миграции (обновление столбцов counter_cache, которые я добавляю).

Я посмотрел http://guides.rubyonrails.org/migrations.html, но примеры в конце раздела 5 страдают от одной и той же проблемы:

class AddFuzzToProduct < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end
  def change
    add_column :products, :fuzz, :string
    Product.reset_column_information
    Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
  end
end

Когда эта миграция отменяется, обновление поля fuzz не требуется. Есть ли способ предотвратить это?

Я попробовал посмотреть Product.column_names, но поскольку Rails достаточно умен, чтобы выполнить миграцию в обратном направлении, обновление выполняется до удаления столбца. Кроме того, когда метод change определен, любые методы up или down кажутся проигнорированными. Любые другие идеи?

4b9b3361

Ответ 1

В этом случае, я думаю, вам придется использовать методы up и down, как обычно. Не беспокойтесь, несмотря на добавление change в Rails 3, эти методы, насколько мне известно, не привязаны к блоку прерывания. Продолжайте использовать их там, где это необходимо.

Изменить: Здесь есть опция: Переопределить migrate.

class AddFuzzToProduct < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end

  def change
    add_column :products, :fuzz, :string
  end

  def migrate(direction)
    super # Let Rails do its thing as usual...

    if direction == :up # ...but then do something extra if we're going 'up.'
      Product.reset_column_information
      Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
    end
  end
end

Мысли?

Ответ 2

Только для справок в будущем, для Rails 4 лучший способ сделать это - использовать обратимый:

def change
  # ...change code...

  reversible do |dir|
    dir.up do
      # ...up-only code...
    end
  end
end

См. http://guides.rubyonrails.org/migrations.html#using-reversible

Ответ 3

В rails 3.x вы также можете сделать это

class AddFuzzToProduct < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end
  def change
    add_column :products, :fuzz, :string
    unless reverting?
      # Do this only when direction is up
      Product.reset_column_information
      Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
    end
  end
end

Ответ 4

Здесь неприятная мысль: @connection - CommandRecorder при спуске вниз.

def change
    add_column :products, :fuzz, :string
    unless @connection.kind_of?(ActiveRecord::Migration::CommandRecorder)
        Product.reset_column_information
        Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
    end
end

Не пробовал. Очевидно, что вы находитесь за пределами Rails API, чтобы он мог сломаться в любое время.

Если только метод изменения имел законный способ определения направления миграции...