Rails迁移:在创建另一个表的条目时更新现有记录

3

我正在尝试为我的Rails应用程序设置Beta邀请。我有一个邀请模型和一个用户模型。

用户有一个invitation_id。我正在验证用户必须拥有invitation_id,并且它应该是唯一的。我想编写一个迁移,以便我可以更新现有用户的invitation_id。

这是我的邀请模型:

# Table name: invitations
#
#  id              :integer         not null, primary key
#  sender_id       :integer
#  recipient_email :string(255)
#  token           :string(255)
#  sent_at         :datetime
#  created_at      :datetime
#  updated_at      :datetime

为了保证唯一性,我将不得不在邀请表中创建记录,并将相应的ID分配给用户记录。
有人能否建议相应的迁移操作?
提前感谢!
1个回答

7
如果您已经完成了邀请和用户的迁移,建议您将邀请生成过程放入自定义的Rake任务中。将迁移严格限制在表操作上是一个好习惯。
/lib/tasks/distribute_invitations.rake
namespace :db do
  desc "Run all custom tasks"
  task :import_all => [:distribute_invitations, :some_other_data_import]

  desc: "Some other data import"
  task :some_other_data_import => :environment do
    puts "insert task code here"
  end

  desc: "Give existing user's invitations"
  task :distribute_invitations => :environment do
    for user in User.all
      if user.invitation_id.nil?
        invite = Invitation.create(:sender_id => <some id>, :recipient_email => <some email>, :token => <some token>, :sent_at => Time.now)
        user.update_attribute(:invitation_id, invite.id)
        puts "Updated user #{user.id} with invitation_id #{invite.id}"
      else
        puts "User already has an invitation_id"
      end
    end
  end
end

在将用户表迁移到具有邀请ID的模式后,您可以运行以下命令:

rake db:distribute_invitations

您现有的用户将通过邀请ID创建并关联到邀请。

或者您可以运行所有任务:

rake db:import_all

在这种情况下,很可能只需要将它与用户迁移一起插入:

class AddInvitationID < ActiveRecord::Migration
  def self.up
    add_column :users, :invitation_id, :integer
    for user in User.all
      if user.invitation_id.nil?
        invite = Invitation.create(:sender_id => <some id>, :recipient_email => <some email>, :token => <some token>, :sent_at => Time.now)
        user.update_attribute(:invitation_id, invite.id)
        puts "Updated user #{user.id} with invitation_id #{invite.id}"
      else
        puts "User already has an invitation_id"
      end
    end
  end

  def self.down
    remove_colum :users, :invitation_id
  end
end

谢谢Chris。这是一个很好的解决方案。出于好奇,为什么我们不使用迁移来完成它?所有正在开发此应用程序的同事(以及潜在的合作者)都必须单独运行rake db:distribute_invitations才能使其在他们的系统中正常工作。 - Nirav Shah
刚刚通过噩梦般的经历学到,每当迁移中存在种子数据依赖时,我总是后悔不已。这使得跟踪变得更加困难,并且不能重新运行任务(如果有必要的话)。我曾在团队环境中工作过,每当我们需要运行自定义任务以填充现有表中的数据时,我们总是会寻找 /lib/tasks。如果您或其他人需要执行相同的操作,只需将其附加到文件中,以便所有数据操作都集中在一起。 - Chris Barretto
1
添加了迁移解决方案和更加强大的Rake任务。 - Chris Barretto
谢谢Chris!我能够根据你提供的细节想出一个解决方案。 - Nirav Shah
你忘记在rake任务中添加:environment依赖。在这种情况下,无法定义你的model。请更新以避免其他人复制你的代码时出现错误。 - shingara
感谢 shingara。为了更加清晰,我添加了这句话。 - Chris Barretto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接