运行before_create的Rails用于现有数据库记录

时间:2017-08-02 14:22:47

标签: ruby-on-rails activerecord

我在数据库中已有一堆character个模型。每个character has_one :iconfolio。我迁移了数据库以将icon_urlpost_url属性添加到iconfolio模型,因此我尝试使用rails控制台更新数据库中的所有iconfolio模型。

但是,为每个现有记录设置正确的属性并非易事,因此我还添加了before_createiconfolio,这将正确设置icon_url和{新post_urlcharacters的{​​1}}属性。但是,如何强制此代码执行数据库中已存在的iconfolioscharacters

在我尝试的控制台中:

iconfolios

但它不会更新数据库。它似乎删除了记录:

Character.all.find_each do |char|
  char.create_iconfolio
end

我也尝试过:

(0.4ms)  COMMIT
Iconfolio Load (0.2ms)  SELECT  "iconfolios".* FROM "iconfolios" WHERE "iconfolios"."character_id" = $1 LIMIT 1  [["character_id", 46]]
(0.1ms)  BEGIN
SQL (0.2ms)  DELETE FROM "iconfolios" WHERE "iconfolios"."id" = $1  [["id", 46]]

这产生了:

Character.all.find_each do |char|
  Iconfolio.create(character_id: char.id)
end

看起来很有前景,但数据库仍未更新。 (我已尝试重启服务器等)。

我做错了什么?

iconfolio.rb

(0.2ms)  BEGIN
Character Load (0.6ms)  SELECT  "characters".* FROM "characters" WHERE "characters"."id" = $1 LIMIT 1  [["id", 2]]
SQL (0.5ms)  INSERT INTO "iconfolios" ("character_id", "created_at", "updated_at", "person_url", "followed_url", "icon_url", "post_url") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["character_id", 2], ["created_at", "2017-08-02 13:27:35.897842"], ["updated_at", "2017-08-02 13:27:35.897842"], ["person_url", "/assets/icon1.png"], ["followed_url", "/assets/icon2.png"], ["icon_url", "/assets/icon7.png"], ["post_url", "/assets/icon8.png"]]
(0.4ms)  COMMIT

2 个答案:

答案 0 :(得分:2)

我喜欢做的是将before_create移动到方法

class Iconfolio
  belongs_to :character
  validates :character_id, presence: true
  before_create :set_attributes 

  def set_attributes
    if self.character.type.is_a? User
      self.icon_url = '/assets/icon5.png'
      self.post_url = '/assets/icon6.png'
    else
      self.icon_url = '/assets/icon7.png'
      self.post_url = '/assets/icon8.png'
    end
  end
end

现在您可以在需要时随时拨打电话

答案 1 :(得分:1)

当我评论你的问题时,你不应该使用Rails'控制台更新现有数据以尊重新的数据库结构(我可以提供示例,如果您需要,不应该这样做)。

您应该在更改de DB结构的完全相同的迁移中更新此数据:

# 1234_your_migration.rb
def up
  # changing the DB structure
  add_column :iconfolios, :icon_url, :string
  add_column :iconfolios, :post_url, :string

  # updating the current data
  Iconfolio.includes(:character).find_each do |iconfolio|
    if self.character.type.is_a? User
      self.icon_url = '/assets/icon5.png'
      self.post_url = '/assets/icon6.png'
    else
      self.icon_url = '/assets/icon7.png'
      self.post_url = '/assets/icon8.png'
    end
  end
end

这可能是一次繁重的迁移,具体取决于您在数据库中拥有的Iconfolio记录的数量。您可以按此处所示执行或定义方法Iconfolio#update_icon_and_post_urls,但此方法仅在Iconfolio创建的上下文中或在迁移中使用,因此可能过度使用,从长远来看污染您的Iconfolio模型重要的是,在重新运行迁移时可能会导致问题(请参阅我对该答案的评论)。