【问题标题】:Adding new field to pre-existing table and modifying previously created data in Rails向预先存在的表添加新字段并修改 Rails 中先前创建的数据
【发布时间】:2011-01-08 23:56:28
【问题描述】:

所以我有一个用户模型和一个相应的表(用户),其中包含以下字段:User_id、用户名、密码等。

但后来我在 users 表中添加了邀请限制。新创建的用户具有invitation_limit,但是在运行invitation_token 迁移之前创建的用户没有invitation_limit 字段。

如何更新之前创建的用户以包含invitation_token 字段?请注意,我不是在谈论向用户表添加邀请限制字段(即迁移),而是更新已创建的用户。

谢谢,

【问题讨论】:

    标签: mysql ruby-on-rails sqlite migration


    【解决方案1】:

    不应将种子数据放入迁移中。迁移是用于创建结构,而不是添加数据,如果您移动数据库,将会遇到问题。

    你可以写一个 rake 任务。如果您创建一个名为“generate_invitation_token”之类的实例方法,那么您可以编写一个像这样的 rake 任务:

    # lib/tasks/invitation_tokens.rake
    namespace :seed do
      desc "generate invitation tokens for users that don't have one already"
      task :user_tokens => :environment do
        User.all(:conditions => {:invitation_token => nil}).each do |user|
          user.generate_invitation_token
        end
      end
    end
    

    然后您可以像这样从命令行调用 rake 任务:

    rake seed:user_tokens
    

    这是一种更简洁的方法。

    更新

    我在一篇名为“Adding Columns and Default Data To Existing Models”的博文中扩展了这个答案。

    【讨论】:

      【解决方案2】:

      不幸的是,对此普遍接受的策略是添加另一个填充这些字段的迁移。当然,您不能使用活动记录(否则您的迁移可能会中断),因此最佳做法是在 pure SQL 中执行此操作。

      【讨论】:

      • 我明白了。这行得通吗? User.find(:all).each 做 |p| p.update_attribute :invitation_limit, 5 end
      • 这行得通,但这不是我在回答中提到的最佳实践,因为它引用了一个模型,严格来说,该模型将来可能会被删除或重命名,从而导致您的迁移失败。跨度>
      • 谢谢,我会使用上面提到的 rake 任务。
      【解决方案3】:

      我的理解是您想要更新用户记录,而不是创建种子(种子将数据添加到您的数据库,例如角色等,这对您的应用程序很重要)。来自documentaion

      class AddReceiveNewsletterToUsers < ActiveRecord::Migration
        def self.up
          change_table :users do |t|
            t.boolean :receive_newsletter, :default => false
          end
          User.update_all ["receive_newsletter = ?", true]
        end
      
        def self.down
          remove_column :users, :receive_newsletter
        end
      end
      

      您也可以在迁移中使用您的模型:

      User.all(:conditions => {}).each do |user|
        user.do_sth
        user.save
      end
      

      等等,阅读about caveats

      编辑:
      在您发表评论后,我认为您应该在迁移中这样做;

      class AddInvitationLimitToUser < ActiveRecord::Migration
        def selt.up
          change_table :users do |t|
            t.integer :invitation_limit # and add validation to model `validates_presence_of` and so on
          end
          # now update all records already in database, which didn't had value in invitation_limit column
          User.update_all ["invitation_limit = ?", 5]
        end
      
        def self.down
          remove_column, :users, :invitation_limit
        end
      end
      

      【讨论】:

      • 好吧,我想在创建用户后向我的用户表添加一个新字段。我创建了用户模型,然后在 users 表中添加了invitation_limit 字段,因此在迁移新字段之前创建的用户不会有新字段。我想更新这些用户并添加invitation_limit 并将它们设置为5。
      • @Senthil 用户在迁移新字段之前创建的新字段将具有新字段,他们只是没有值(默认为 NULL)。它们位于您已经修改过的同一张表中,因此它们不会因为之前创建的而错过新字段(列)。
      • 你是对的,它确实被创建了。我猜我之前遇到的错误是它说它是 NULL 而不是它没有被创建。谢谢!
      【解决方案4】:

      您想为此使用迁移。迁移只是 ruby​​ 代码,因此您可以访问应用程序可以访问的所有数据。更改数据、添加缺失数据、删除行等。

      一些快速提示:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-29
        • 1970-01-01
        • 1970-01-01
        • 2016-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多