Реализация будет отличаться в зависимости от целевой базы данных. Postgres, например, изначально поддерживает upserts через INSERT ... ON CONFLICT UPDATE . Вы должны обратиться к документации вашей базовой базы данных для подробностей. В общем, однако, ActiveRecord попытается использовать все уникальные индексы в таблице, чтобы определить, конфликтует ли существующая запись или нет. Как минимум, это означает, что ваш первичный ключ, хотя это может означать и другие. Если вы используете Postgres или SQLite, вы можете передать :unique_by
для подтверждения, чтобы явно указать, какие поля следует использовать, чтобы определить, существует ли соответствующая запись ( doc ). Обратите внимание, что если вы используете это и попытаетесь вставить запись, которая конфликтует с другой записью по уникальному ключу, не указанному в unique_by
, ваша база данных выдаст исключение.
Я получу NotNullViolation, потому чтов идентификаторе есть нулевое значение, которое я не указываю.
Нет, конечно, нет - вы должны указать все поля, которые будут вставлены во время вставки при выполнении upsert, потому что, очевидно, если запись не существует и должна быть вставлена, она должна содержатьвсе необходимые поля. Если у вас есть поля, указанные как ненулевые, вы не можете попытаться их удалить, когда вставленное значение будет нулевым!
Поскольку вы не передаете идентификатор, Rails не может понять, как определитьуникальность записи. Он может работать с уникальным индексом в одном из других ваших полей (при условии, что уникальный индекс подходит для вашего приложения).