创建外键时列名称的多次复制错误

时间:2016-04-07 15:06:58

标签: ruby-on-rails activerecord foreign-keys inflection

我在使用Rails 4.2.4时遇到了一个奇怪的问题。我正在创建一个新表,引用其他一些表,如下所示:

t.references :local, index: true, foreign_key: true, null: false
t.references :serie, index: true, foreign_key: true, null: false

执行迁移时,创建外键约束时出错:

  

PG :: UndefinedColumn:ERROR:no existe la columna«series_id»referida en lallaveforánea

这是西班牙语

  

PG :: UndefinedColumn:ERROR:外键约束中引用的列«series_id»不存在

表示创建的表中没有“series_id”列。当然,它不应该是具有该名称的任何列。

FK生成应该寻找的正确列名是“serie_id”,它确实存在。

现在最奇怪的是它不会失败:例如,本地。它不会查找“locales_id”,而是查找正确的“local_id”,并创建相应的FK。

我有自定义的西班牙语变形,正确的复数是:

  

local - >区域设置

     

serie - >系列

然而我不明白为什么FK一代在一种情况下似乎是多元化而在另一种情况下却不是。

我在this answer找到了一个可行的解决方案,它特意声明了外键,例如:

add_foreign_key :turnos_registrados, :series, column: :serie_id

但我想知道的是为什么会发生这种情况。

提前致谢。

2 个答案:

答案 0 :(得分:3)

似乎Rails执行此过程来获取外键列名:

迁移中引用的模型→(将符号转换为字符串)→复数 singularize

在找到给定引用模型的表名时完成复数化,请参阅this line in the source code。然后,在从先前多元化的表名派生实际外键列时完成单一化(参见source here)。

然而,在英语中,“系列”是collective noun,因此单数和复数形式是相同的。 Rails默认处理这个问题:

"serie".pluralize
# => "series"

但也请注意:

serie

因此,首先将“s”附录添加到:serie引用的模型名称中,然后单数化产生相同的单词 - “系列”。即Rails从您的迁移中为:serie → "serie" (conversion to string) → "series" (pluralize) → "series" (singularize) 引用的模型产生以下内容:

series_id

因此,这就是Rails尝试查找locales_id外键列而不是add_foreign_key的原因。

您写道,您设法使用series_id手动添加了正确的密钥。我怀疑您稍后会遇到更多设置问题,因为Rails仍会尝试将外键导出为serie_id

您必须在关联中的任何位置指定正确的(ActiveSupport::Inflector.inflections do |inflect| inflect.irregular 'serie', 'series' end )foreign_key,或者您应为您的案例定义自定义复数规则。该规则应添加为包含以下内容的初始化程序:

"series".singularize
# => "serie"

一旦你有了这个,复数将按照你的具体情况按预期工作:

{{1}}

使用这个自定义规则,我认为即使您的原始迁移也应该没有问题。

答案 1 :(得分:1)

感谢BoraMa's answer,我进一步发现了“为什么”:

似乎一些高优先级的Rails默认英语变形正在阻碍。

我有一个变形规则

inflect.singular(/((?<![aeiou][rndlj])e|a|i|o|u)s([A-Z]|_|$)/, '\1\2')

应该抓住

"series".singularize

因为

2.2.1 :006 > "series".gsub(/((?<![aeiou][rndlj])e|a|i|o|u)s([A-Z]|_|$)/,'\1\2')
=> "serie" 

但它没有用。不知何故,添加建议的

inflect.irregular 'serie', 'series'

使它工作,但它应该没有。所以,我怀疑一些预先定义的规则,可以在控制台中确认(另一个BoraMa的贡献),因为对句子的回应

ActiveSupport::Inflector.inflections.singulars

将打印其他:[/(s)eries $ / i,“\ 1eries”]。

为了摆脱这些默认值,添加

  inflect.clear

到inflections.rb成功了。现在它适用于我最初的一般规则。