Rails 3迁移:如何添加引用列?

162
如果我使用以下命令创建一个新的 Rails 3 数据迁移文件(例如):
rails g migration tester title:tester user:references

一切工作正常...但是如果我添加一个类似以下的列:

rails g migration add_user_to_tester user:references

引用字段未被识别。简而言之,问题是:如何通过命令行向Rails迁移添加引用列?

10个回答

205

如果你使用的是 Rails 4.x,你现在可以生成带有引用的迁移,就像这样:

rails generate migration AddUserRefToProducts user:references

就像你可以在Rails指南上看到的那样


1
请参考 http://edgeguides.rubyonrails.org/active_record_migrations.html 的第2.1节作为示例。 - B Seven
2
如何指定外键的列名而不是自动生成的名称? - j will
@jwill 你可以使用多态:user:references{polymorphic}。 - Paulo Fidalgo
@PauloFidalgo,你能稍微解释一下如何做到这一点吗?可能有一些链接或指南吗?(谈论多态性) - Anwar
@Anwar:这里是文档链接 http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-references - Paulo Fidalgo

186

编辑:本回答已过时,不应用于Rails 4.x+

当你可以使用整数id引用类时,就不需要添加引用了。

我认为使用引用而不是普通整数的优点在于,该模型将预定义为belongs_to,并且由于该模型已经创建,当您迁移现有内容时,它将不受影响,因此其目的有些失去意义。

所以我会像这样做:

rails g migration add_user_id_to_tester user_id:integer

然后在Tester模型中手动添加belongs_to :user


9
但这样做不会在支持外键约束的数据库中创建适当的外键约束,对吗? - abahgat
19
不,据我所知,Rails在数据库上从不创建外键约束,除非您添加插件来为您执行此操作。 - DanneManne
13
记得将索引添加为user:integer:index。 - rickypai
3
回答已经过时,请查看@Paulo的回答获取现代版的Rails。 - OneHoopyFrood
@abahgat 在 Rails > 4.2 中,现在有一个 add_foreign_key 方法,可以方便地在数据库级别上添加外键约束。 - Drew
显示剩余4条评论

103
请注意,你很可能还需要在那一列上创建一个索引。
class AddUserReferenceToTester < ActiveRecord::Migration
  def change
    add_column :testers, :user_id, :integer
    add_index  :testers, :user_id
  end
end

1
为什么?这对大多数belongs_to关系都适用吗? - ahnbizcad
出于性能原因确实需要这样做,如果您在belongs_to关系的另一侧有一个has_many/has_one,那么这将非常方便。如果您绝对确定不会通过"user.testers"访问它,则可以省略索引。 - Евген
1
rails g migration ... 生成了 add_reference :installs, :device, index: true,它还会创建索引。 - B Seven

49

在执行前两个步骤后,您仍然缺少外键约束。这将起作用:

  class AddUserReferenceToTester < ActiveRecord::Migration
      def change
          add_column :testers, :user_id, :integer, references: :users
      end
  end

这是唯一正确的答案。外键是最关键的部分。 - user2490003
这应该被标记为正确答案,因为问题要求Rails 3。 - Carlos Roque

35

在变更迁移中,您可以使用引用。这是有效的Rails 3.2.13代码:

class AddUserToTester < ActiveRecord::Migration
  def change
    change_table :testers do |t|
      t.references :user, index: true 
    end
  end
  def down
    change_table :testers do |t|
      t.remove :user_id
    end
  end
end

参考: http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/change_table

该链接提供了有关Rails ActiveRecord中change_table方法的文档。

1
更改和下降方法?难道不应该是上升和下降方法吗? - MaicolBen
@MaicolBen 是的,你也可以只省略 down 方法。 - Hut8
@MaicolBen 在Rails 3.2中回滚时,如果没有使用down方法,我会遇到ActiveRecord::IrreversibleMigration错误。我还必须将change更改为up - Andrew Grimm

27

运行rails g migration AddUserRefToSponsors user:references会生成以下迁移:

def change
  add_reference :sponsors, :user, index: true
end

这是哪个版本的Rails? - Andrew Grimm

8
那就做到了:
rails g migration add_user_to_tester user_id:integer:index

我喜欢这个功能还会添加你最可能需要的索引。 - bheeshmar

8

添加列时,需要将该列设为整数,并尽可能遵循Rails的约定。所以对于你的情况,我假设你已经有了Tester和User模型,以及testers和users表。

要添加外键,需要创建一个名为user_id(约定)的整数列:

add_column :tester, :user_id, :integer

然后在测试人员模型中添加一个belongs_to:
class Tester < ActiveRecord::Base
  belongs_to :user
end

你可能还想为外键添加一个索引(这是引用已经为你完成的):

add_index :tester, :user_id

3

针对Rails 4

生成器接受列类型作为引用(也可用作belongs_to)。

此迁移将创建一个user_id列和相应的索引:

$ rails g migration AddUserRefToProducts user:references 

生成:

class AddUserRefToProducts < ActiveRecord::Migration
  def change
    add_reference :products, :user, index: true
  end
end

http://guides.rubyonrails.org/active_record_migrations.html#creating-a-standalone-migration

Rails 3

在Rails 3中,帮助程序被称为references(也可作为belongs_to使用)。

此迁移将创建一个适当类型的category_id列。请注意,您传递的是模型名称,而不是列名称。Active Record会自动添加_id

change_table :products do |t|
  t.references :category
end

如果您有多态的belongs_to关联,那么references将添加所需的两个列:

change_table :products do |t|
  t.references :attachment, :polymorphic => {:default => 'Photo'}
end

将添加一个附件 ID 列和一个字符串 attachment_type 列,并将默认值设置为 Photo点击此处了解更多。

3
您可以通过命令行以以下方式向您的模型添加引用:
rails g migration add_column_to_tester user_id:integer

这将生成一个类似于以下的迁移文件:
class AddColumnToTesters < ActiveRecord::Migration
  def change
    add_column :testers, :user_id, :integer
  end
end

每次我使用它时,它都可以正常工作。


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