在 Rails 迁移中更新属性值

Updating Attribute Value in Rails Migration

我通过 ActiveAdmin (http://activeadmin.info/) 上传了 100 多个具有以下属性的食谱:

class CreateRecipes < ActiveRecord::Migration
  def change
    create_table :recipes do |t|
      t.string :title
      t.string :description
      t.string :ingredients
      t.string :position

      t.timestamps
    end
  end
end

我需要将位置从字符串更改为整数。我能够通过以下方式做到这一点:

change_column :table_name, :column_name,  :integer  

计算器溢出:Rails migration for change column

问题是我不知道如何返回并为所有食谱重新分配一个位置(现在它是一个整数)。我基本上想从 0 开始一直到 100。如果我创建一个新食谱,它会自动具有 101 的位置值。

有没有办法做到这一点而无需返回并单独更改每个食谱?

听起来您最初想将 :position 设置为 :id。您可以像这样通过 rails 控制台执行此操作:

recipes = CreateRecipes.all
recipes.each do |recipe|
  recipe.position = recipe.id
end

然后,对于新食谱,您可以在您的模型 (create_recipes.rb) 中添加:

after_initialize :default_values
...
def default_values
  self.position ||= id
end

顺便说一句,这是处理默认值或一般初始值的一种非常干净的方法。有关更多信息,请参阅这个优秀的 post How can I set default values in ActiveRecord?.

您可以将转换 运行 作为迁移本身的一部分自动进行。添加代码以将现有记录中的值转换为迁移。使用 self.up 和 self.down 为该迁移方向提供适当的转换代码:

class ChangeRecipePositionToInteger < ActiveRecord::Migration
  def self.up
    position_values = Hash[ Recipe.all.map{|r| [r.id, r.position]}]

    change_column :recipes, :position, :integer

    position_values.each_pair do |id, position_value|
      recipe = Recipe.find( id )
      recipe.position = position_value.to_i
      recipe.save
    end
  end

  def self.down
    position_values = Hash[ Recipe.all.map{|r| [r.id, r.position]}]

    change_column :recipes, :position, :string

    position_values.each_pari do |id, position_value|
      recipe = Recipe.find( id )
      recipe.position = position_value.to_s
      recipe.save
    end
  end
end