Некорректное добавление имени столбца при создании внешнего ключа

У меня странная проблема с 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: нет существующего столбца "серийный_идентификационный номер").

что по-испански

PG::UndefinedColumn: ERROR: столбец "series_id", на который ссылается ограничение внешнего ключа, не существует

это означает, что в созданной таблице нет столбца "series_id". Конечно, это не должен быть какой-либо столбец с таким именем.

Правильное имя столбца, которое должно искать поколение FK, - "serie_id", и оно существует.

Теперь самое странное в том, что он не ошибается: например, локальный. Он ищет не "locales_id", а "local_id", который является правильным, и создается соответствующий FK.

У меня есть пользовательские интонации испанского языка, и правильные множественные числа:

местные -> локали

серия -> серия

однако я не понимаю, почему поколение ФК, похоже, плюрализуется в одном случае, а не в другом.

В этом ответе я нашел работающее решение, которое объявляет конкретно внешние ключи, например:

add_foreign_key :turnos_registrados, :series, column: :serie_id

но я хотел бы знать, почему это происходит.

Заранее спасибо.

2 ответа

Решение

Кажется, что Rails делает эту процедуру, чтобы получить имя столбца внешнего ключа:

ссылочная модель в миграции → (преобразовать символ в строку) → множественное числоединственное число

При определении имени таблицы для данной ссылочной модели выполняется множественное число, см. Эту строку в исходном коде. Затем выполняется сингуляризация при получении фактического столбца внешнего ключа из ранее умноженного имени таблицы (см. Источник здесь).

Тем не менее, в английском языке "серия" является собирательным существительным, поэтому формы единственного и множественного числа совпадают. Rails обрабатывает это правильно по умолчанию:

"series".pluralize
# => "series"

"series".singularize
# => "series"

Но также обратите внимание на это:

"serie".pluralize
# => "series"

Итак, приложение "s" сначала добавляется в serie упомянутое имя модели, а затем сингуляризация приводит к тому же слову - "серия". Т.е. Rails выдает следующее для :serie Ссылочная модель из вашей миграции:

: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"

И с этим пользовательским правилом я думаю, что даже ваша оригинальная миграция должна работать без проблем.

Благодаря ответу 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 сделал это. Теперь это работает с более общим правилом, которое у меня было изначально.

Другие вопросы по тегам