Транзакция Rails не откатывается при ошибке проверки - PullRequest
11 голосов
/ 11 февраля 2010

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

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

Спасибо

Ответы [ 5 ]

2 голосов
/ 29 марта 2010

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

show table status\G

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

ALTER TABLE <table name> ENGINE INNODB;

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

1 голос
/ 15 августа 2011

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

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

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

0 голосов
/ 02 апреля 2010

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 никогда не будет выполнена.

0 голосов
/ 11 марта 2010

Вам нужно будет рассмотреть эти сценарии

  1. Использовать систему базы данных, которая поддерживает транзакции
  2. Перефакторинг этого кода для более логичного подхода

Например, если у вас есть только однозначное отношение, оно может обрабатываться более оптимизированным способом

Company has_one User
User belongs_to Company

В настоящее время в компании модель

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

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

0 голосов
/ 07 марта 2010

http://tempe.st/2007/05/transaction-in-rails/

Я считаю, что вы должны использовать начальный конечный блок вне цикла транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...