1

我对 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 la llave foránea

这是西班牙语

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

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

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

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

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

本地 -> 语言环境

系列 -> 系列

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

我在这个答案中找到了一个可行的解决方案,它专门声明了外键,例如:

add_foreign_key :turnos_registrados, :series, column: :serie_id

但我想知道的是为什么会这样。

提前致谢。

4

2 回答 2

3

似乎 Rails 执行此过程是为了获取外键列名称:

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

在为给定的引用模型查找表名时完成复数,请参见源代码中的这一行然后,在从先前的复数表名派生实际外键列时完成单数化(请参阅此处的源代码)。

但是,在英语中,“series”是一个集合名词,所以单数和复数形式是一样的。默认情况下,Rails 会正确处理此问题:

"series".pluralize
# => "series"

"series".singularize
# => "series"

但也要注意这一点:

"serie".pluralize
# => "series"

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

:serie → "serie" (conversion to string) → "series" (pluralize) → "series" (singularize)

所以这就是为什么 Rails 试图寻找series_id外键列而不是locales_id.

您写道,您设法使用add_foreign_key. 我怀疑您稍后会遇到更多设置问题,因为 Rails 仍会尝试将外键导出为series_id.

您必须在关联中的任何位置指定正确的 ( serie_id) foreign_key,或者您应该为您的案例定义一个自定义复数规则。该规则应作为初始化程序添加,其中包含:

ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular 'serie', 'series'
end

一旦你有了这个,复数形式将按你的特定情况工作:

"series".singularize
# => "serie"

有了这个自定义规则,我认为即使是您最初的迁移也应该没有问题。

于 2016-04-07T16:46:38.437 回答
1

感谢BoraMa 的回答,我走得更远,发现了“为什么”:

似乎有一些高优先级的 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 做到了。现在它适用于我最初拥有的更一般的规则。

于 2016-04-09T17:41:57.510 回答