Подтвердить что ты не робот

Операция Rails не откатывается при ошибке проверки

У меня две модели: пользователь и компания. Они оба создаются из одной формы, и я использую транзакцию следующим образом:

 User.transaction do

  @user.save!

  @company.user = @user
  @company.save!

  @user.reload
  @user.company = @company
  @user.save!

 flash[:notice] = "Thank you for your registration."
  redirect_to_index
end

Пользователь получает сохранение в базе данных даже в случае сбоя одной из проверок компании. Я попытался добавить явную обработку ошибок ActiveRecord:: RecordInvalid, но это не помогло. Я думал, что проверка приведет к ошибке при откате транзакции. Любая помощь приветствуется.

Спасибо

4b9b3361

Ответ 1

Вы должны использовать механизм базы данных, поддерживающий транзакции ACID. Для mysql это INNODB.

show table status\G

Если пользователи или компании не используют движок InnoDB, вы можете изменить его с помощью этой команды.

ALTER TABLE <table name> ENGINE INNODB;

исключение, созданное из @company.save! *, должно вызывать команду ROLLBACK для отправки в базу данных. вы можете проверить это в файле console/log при запуске script/server с уровнем журнала DEBUG.

Ответ 2

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

if @new_entry.valid? && @existing_entry.valid?
  ActiveRecord::Base.transaction do
    @new_entry.save!
    @existing_entry.save!
  end
end

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

Ответ 3

Вам придется рассмотреть эти сценарии

  • Использовать систему баз данных, поддерживающую транзакцию
  • Re-Factor, что код для более логичного подхода

В качестве примера, если у вас есть только отношение "один к одному", его можно обрабатывать более оптимизированным способом.

Company has_one User
User belongs_to Company

Теперь, в модели компании

@company.user.build(user_attributes)
@company.save  # will save company as well as user

Я не тестировал его в качестве примера. Просто с ума. Я правильно понял проблему?

Ответ 4

save() и destroy() всегда находятся в транзакции (см. http://railsapi.com/doc/rails-v2.3.5/classes/ActiveRecord/Transactions/ClassMethods.html).

Я думаю, что вы хотите сделать

  begin
    @company = Company.create!(params[:company])
    @user    = User.create!(params[:user]) { |user| user.company => @company }
  rescue => ex
    # ... handle your validation errors
  end

Это решит вашу проблему, так как при отказе компании исключение исключений будет вызвано, и инструкция User.create никогда не будет выполнена.