在“引用”迁移中指定列名

Posted

技术标签:

【中文标题】在“引用”迁移中指定列名【英文标题】:Specifying column name in a "references" migration 【发布时间】:2012-11-21 14:12:23 【问题描述】:

我想在 Rails 中创建一个migration,引用另一个表。通常,我会这样做:

add_column :post, :user, :references

这会在posts 表中创建一个名为user_id 的列。但是,如果我想要author_id 之类的东西而不是user_id,该怎么办?我该怎么做?

【问题讨论】:

【参考方案1】:

在 rails 4 中,当使用 postgresql 和 schema_plus gem 时,您可以编写

add_reference :posts, :author, references: :users

这将创建一个列author_id,它正确地引用了users(id)

在你的模型中,你写

belongs_to :author, class_name: "User"

注意,新建表的时候可以这样写:

create_table :things do |t| 
  t.belongs_to :author, references: :users 
end 

注意:schema_plus gem 整体上与 rails 5+ 不兼容,但此功能由与 rails 5 兼容的 gem schema_auto_foreign_keys(schema_plus 的一部分)提供。

【讨论】:

如果您使用的是create_tablet.references :author, references: :users 将@MichaelRadionov 的评论添加到您的答案中会更完美。 我一直在查看 Rails 4.1 源代码,但找不到任何证据表明 :references 确实做了任何事情。 是的,你是对的,我使用schema_plus gem 已经很久了,它实际上是在添加这个功能。我相应地编辑了我的答案。 在 Rails 6 中,t.references :col_name, references: other_table_name 语法似乎可以在不安装额外 gem 的情况下工作。【参考方案2】:

Rails 4.2+中,您还可以在数据库中设置foreign keyswhich is a great idea。

对于简单的关联,这也可以在 t.references 添加 foreign_key: true 上完成,但在这种情况下,您需要两行。

# The migration
add_reference :posts, :author, index: true
add_foreign_key :posts, :users, column: :author_id

# The model
belongs_to :author, class_name: "User"

【讨论】:

谢谢,但问题标记为 Rails3,我很乐意提供帮助 哦,我没注意到。嗯,这对我很有帮助。 :) 当我看到这个时,我几乎要放弃希望了!谢谢@ecoologic! @ecoologic,您可能想要添加的只是一件事,add_foreign_key 仅是 rails 4.2+。 ;) 我不确定您是否需要 add_reference 调用中的 references: :users 选项。我没有在文档中看到它的记录,如果没有它,它似乎对我有用。【参考方案3】:

alias_attribute(new_name, old_name) 非常方便。 只需创建您的模型和关系:

rails g model Post title user:references

然后编辑模型并添加属性别名

alias_attribute :author, :user

之后你就可以运行类似的东西了

Post.new(title: 'My beautiful story', author: User.first)

【讨论】:

这在您需要定义对另一个模型的多个引用时不起作用,例如,post (author, editor)【参考方案4】:

适用于 Rails 5+

初始定义:

如果你定义你的Post模型表,你可以在一行中设置referencesindexforeign_key

t.references :author, index: true, foreign_key:  to_table: :users 

更新现有:

如果您要添加对现有表的引用,您可以这样做:

add_reference :posts, :author, foreign_key:  to_table: :users 

注意: index 的默认值为 true。

【讨论】:

初始定义是否允许空值?如果没有,你知道可以为空的替代方案吗? 这个定义允许nulls。要不允许它们,请添加常用选项 null: false 谢谢。对于“初始定义”,我认为“索引:真”不是必需的。无论有没有它,我都会得到相同的架构更改。没关系;刚刚在最后看到了你的笔记。 谢谢,这就是我要找的!【参考方案5】:

如果您不使用外键,那么另一个表的实际表名是什么并不重要。

add_reference :posts, :author

从 Rails 5 开始,如果您使用外键,则可以在外键选项中指定其他表的名称。 (请参阅https://github.com/rails/rails/issues/21563 进行讨论)

add_reference :posts, :author, foreign_key: to_table: :users

在 Rails 5 之前,您应该将外键添加为单独的步骤:

add_foreign_key :posts, :users, column: :author_id

【讨论】:

请注意rails g migration AddAuthorToPosts author:references 不能输出这个。您必须手动更新迁移(请参阅:github.com/rails/rails/blob/main/railties/lib/rails/generators/…)【参考方案6】:

手动操作:

add_column :post, :author_id, :integer

但是现在,当你创建belongs_to语句时,你必须修改它,所以现在你必须调用

def post
    belongs_to :user, :foreign_key => 'author_id'
end

【讨论】:

我不需要添加任何索引吗? 是的,您需要在迁移中创建索引。 Rails 作弊 - 默认情况下它并不真正使用索引。现在,如果您想要索引(这是一个好主意 - 尽管 Rails 会完全忽略它们),那么您当然可以添加它们。您将需要查看我链接的指南以获取有关迁移的更多信息,您甚至可能最终将调用 SQL 代码直接放在迁移中。我想说忽略它,因为它不是 rails 的正常部分,你会得到 0 的性能,因为 rails 的默认生成的 SQL 查询没有利用它。 link 嗯明白了。非常感谢! 使用schema_plus gem,t.references :category, index: true, foreign_key: true, references: :match_categories 在迁移文件中也为我工作。

以上是关于在“引用”迁移中指定列名的主要内容,如果未能解决你的问题,请参考以下文章

为啥在列名中指定主/外键属性

在 Liquibase 中指定不同的“TAG”列名

如何在 SQL Server 的交叉应用联接中指定列名

如何使用变量在ggplot中指定列名

在 mysqldump 中指定日期格式

Fluent NHibernate:如何使用约定在组件中指定列名以供参考?