Rails transaction rollback

Не могу понять как откатить все изменения примененные в рамках транзакции.
У меня есть метод который загружает из xml файла данные о клиентах. Перед началом загрузки файла всем клиентам, которых нет в xml файле, проставляется поле validity в false. Потом начинается загрузка клиентов и обновление существующих. Весь метод я обернул в транзакцию. Но если попробовать сделать загрузку заведомо неправильного клиента(который не проходит валидацию) у меня вся транзакция не откатывается. Подскажите что я делаю не так? Как правильно работает транзакции в rails ?
if customers_upload
  EXCHANGE_LOGGER.info("Start customers exchange")
  Customer.transaction do
    begin
      customers = xml.elements.to_a("//customer")

      customers_external_keys = []
      customers.each do |customer| 
        customers_external_keys << customer.elements['external_key'].text
      end          
      customers_false = Customer.where("external_key NOT IN (?)", customers_external_keys)
      customers_false.each do |customer_false|
        if customer_false.validity
          customer_false.update_attributes(validity: false)              
        end
      end
      EXCHANGE_LOGGER.info("#{customers_false.count} update validity in false")

      customers.each do |customer| 
        customer_name = customer.elements['name'].text
        customer_external_key = customer.elements['external_key'].text
        customer_address = customer.elements['address'].text
        customer_debt = customer.elements['debt'].text
        customer_db = Customer.find_by_external_key(customer_external_key)
        if !customer_db
          new_customer = Customer.create(name: customer_name, external_key: customer_external_key, address: customer_address, debt: customer_debt)
          EXCHANGE_LOGGER.info("#Create new customer #{customer_name}")
        else 
          if !customer_db.validity
            customer_db.update_attributes(name: customer_name, address: customer_address, debt: customer_debt, validity: true)
            EXCHANGE_LOGGER.info("#Change validity true and update customer #{customer_name}")            
          else
            customer_db.update_attributes(name: customer_name, address: customer_address, debt: customer_debt)
            EXCHANGE_LOGGER.info("#Update customer #{customer_name}")
          end        
        end
      end

    rescue => e
      if e.present?
        EXCHANGE_LOGGER.error("Customers not exchanged, message: #{e}")
        raise ActiveRecord::Rollback, "Call tech support!"
      end          
    end        
  end  
end


Вот содержимое exchange.log :
2013-11-29 10:53:23 INFO Start customers exchange
2013-11-29 10:53:33 INFO 3981 update validity in false
2013-11-29 10:53:33 ERROR Customers not exchanged, message: undefined method `text' for nil:NilClass

Вот содержимое development.log :
Customer Exists (0.2ms)  SELECT 1 AS one FROM `customers` WHERE (`customers`.`external_key` = 'CB001820' AND `customers`.`id` != 3979) LIMIT 1
   (0.1ms)  UPDATE `customers` SET `validity` = 0, `updated_at` = '2013-11-29 10:53:33' WHERE `customers`.`id` = 3979
  Customer Exists (0.2ms)  SELECT 1 AS one FROM `customers` WHERE (`customers`.`external_key` = 'CB001826' AND `customers`.`id` != 3980) LIMIT 1
   (0.1ms)  UPDATE `customers` SET `validity` = 0, `updated_at` = '2013-11-29 10:53:33' WHERE `customers`.`id` = 3980
  Customer Exists (0.2ms)  SELECT 1 AS one FROM `customers` WHERE (`customers`.`external_key` = 'CB001822' AND `customers`.`id` != 3981) LIMIT 1
   (0.1ms)  UPDATE `customers` SET `validity` = 0, `updated_at` = '2013-11-29 10:53:33' WHERE `customers`.`id` = 3981
   (2.2ms)  SELECT COUNT(*) FROM `customers` WHERE (external_key NOT IN ('12312'))
   (0.1ms)  ROLLBACK

Вроде ROLLBACK под конец появляется, но все клиенты всё равно остаются не валидными:(
  • Вопрос задан
  • 3502 просмотра
Решения вопроса 1
mgyk
@mgyk
В MyISAM нет поддержики транзакции.
ALTER TABLE table_name engine=INNODB;
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@himik
вы в транзакцию засунули всех кастомеров. сделайте транзакцию в том месте, где вы конкретного кастомера обновляете
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы