Почему некоторые данные сохраняются, даже если возникают ошибки?

Как можно предотвратить сохранение типов блокировки, если не указана причина блокировки при внесении изменений в issue в плагине redmine? В нашем патче добавлены новые поля `block_reason` (причина блокировки) - простая текстовая строка и `block_types` (типы блокировки) - связь many-to-many с другой сущностью, реализованная с помощью `has_and_belongs_to_many`. Наш кастомный метод валидации выдает сообщение об ошибке, если тип блокировки выбран, но причина не указана, но при этом тип блокировки всё равно сохраняется. Как можно избежать сохранения типов блокировки, если не указана причина блокировки?
  • 18 января 2024 г. 5:28
Ответы на вопрос 2
Если данные сохраняются даже в случае возникновения ошибок валидации, это указывает на неправильно сконфигурированный механизм валидации или проблему в логике сохранения данных. В системе управления проектами, такой как Redmine, валидация данных должна предотвратить сохранение записи, если во время валидации были обнаружены ошибки.

Чтобы решить проблему с сохранением типов блокировки в вашем случае, необходимо убедиться, что ваш метод валидации корректно работает и отменяет транзакцию сохранения, если обнаруживает ошибки. Вот шаги, которые могут помочь исправить ситуацию:

1. **Проверьте валидацию**: Убедитесь, что метод валидации правильно добавлен в модель и вызывается во время процесса сохранения. Валидация должна быть частью жизненного цикла объекта в ActiveRecord.

```ruby
validate :custom_validation_method

def custom_validation_method
  if block_types.present? && block_reason.blank?
    errors.add(:block_reason, "не может быть пустым, если выбран тип блокировки")
  end
end
```

2. **Используйте транзакции**: Оберните процесс сохранения в транзакцию, чтобы убедиться, что, если происходит ошибка, все изменения откатываются назад.

```ruby
ActiveRecord::Base.transaction do
  issue.save!
end
```

Если `save!`  вызовет исключение (что произойдет, если валидация не пройдена), транзакция будет откачена.

3. **Используйте hooks**: Убедитесь, что валидация реализована через `before_save` или другой подходящий callback, который отрабатывает до фактического сохранения.

```ruby
before_save :ensure_block_reason_provided_if_block_type_set

def ensure_block_reason_provided_if_block_type_set
  if block_types.present? && block_reason.blank?
    throw(:abort)
  end
end
```

Использование `throw(:abort)` в `before_save` callback прервёт цепочку callback'ов и отменит сохранение.

4. **Проверка на уровне контроллера**: Проверьте, что на уровне контроллера также организована проверка валидации перед сохранением.

```ruby
if @issue.valid? && @issue.save
  # Действия в случае успешного сохранения
else
  # Действия в случае ошибки валидации
end
```

Если вы все еще сталкиваетесь с проблемой, проверьте код, который непосредственно взаимодействует с этими атрибутами, и убедитесь, что ничто не обходит стандартные механизмы валидации или изначально не сохраняет данные через какие-либо прямые запросы к базе данных, например, через `update_column` или `update_all`, которые не вызывают колбэки ActiveRecord.

Наконец, поскольку вы работаете с Redmine, который является открытым исходным кодом, убедитесь, что ваши изменения совместимы с системой плагинов Redmine и что вы используете предоставляемые механизмы расширения функциональности для корректной интеграции вашего плагина.
1. 
Вместо
!block_type_ids.count.positive?
лучше
block_type_ids.empty?
И напротив, вместо .empty? использовать .present?

2. проверить, что колбэк валидации срабатывает, поставив точку останова и протрассировать. Убедиться, что модель действительно возвращает false на .valid?
Похожие вопросы