Как распознать направление миграции (вверх или вниз) с миграциями стиля 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
кажутся проигнорированными. Любые другие идеи?
Ответы
Ответ 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, чтобы он мог сломаться в любое время.
Если только метод изменения имел законный способ определения направления миграции...