Отношение
A has_one
не означает, что модель с отношением has_one
принадлежит только одному объекту с отношением belongs_to
. Это не означает, что существует только одна запись chemical_safety_features
с этим work_item_id
.
Вы можете применить это с проверкой уникальности:
class ChemicalSafetyFeature < ActiveRecord::Base
validates :work_item_id, uniqueness: true
belongs_to :work_item
end
Способ, которым работает эта проверка, заключается в запросе базы данных перед сохранением экземпляра ChemicalSafetyFeature
, чтобы проверить, существует ли уже запись с этим work_item_id
. Если запись найдена, она не может быть сохранена. Нарушение этого ограничения все еще возможно из-за состояния гонки.
Представьте, что в базе данных нет конфликтующих записей, и два процесса запрашивают в базе данных запись с work_item_id = 5
, и ни один из процессов не находит никаких записей. Тогда оба процесса сохранят запись с work_item_id = 5
, нарушая ограничение.
Решение состоит в том, чтобы добавить уникальное ограничение в базу данных. Это обеспечит невозможность иметь две записи с одинаковыми значениями work_item_id
.
Создать миграцию с помощью этого add_index
вызова:
add_index :chemical_safety_features, :work_item_id, unique: true
С этим индексом база данных будет применять ограничение, и код приложения не сможет нарушить ограничение.
Вы также должны определить work_item_id
как внешний ключ в базе данных, используя миграцию add_foreign_key
. Это предотвратит вставку значений мусора в это поле. Это также предотвратит потерянные записи - вы не сможете удалить запись из work_items
, если в таблице chemical_safety_features
есть ссылка на эту запись.
Наконец, вы должны указать rails, что делать, если вы вызываете #destroy
для WorkItem
экземпляра, который принадлежит ChemicalSafetyFeature
. Взгляните на параметр dependent
для отношений has_one
и has_many
.
Например, если вы укажете
class WorkItem < ActiveRecord::Base
has_one :chemical_safety_feature, dependent: :destroy
end
Затем вызов #destroy
на WorkItem
вызовет destroy
на соответствующий ChemicalSafetyFeature
. Другие значения для опции dependent
: :delete
, :nullify
, :restrict_with_exception
и :restrict_with_error
.
.
Рекомендуется всегда указывать параметр dependent
для всех отношений has_one
и has_many
.