I have a method that loads from xml file customers. Before the file download all customers that are not in xml file is put in the validity false. Then begins loading and updating of existing customers . I wrapped the whole method in a transaction. But if you try to make the download client deliberately wrong ( which does not pass validation) I have not the entire transaction is rolled back. Prompt what am I doing wrong ? How to work in a transaction rails?
Code:
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
Here are the contents in 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
Here are the contents development.log:
Customer Exists (0.2ms) SELECT 1 AS one FROM
customers
WHERE (customers
.External_key
= 'CB001820' ANDcustomers
.Id
! = 3979 ) LIMIT 1 (0.1ms) UPDATEcustomers
SETvalidity
= 0 ,updated_at
= '2013- 11 -29 10:53:33 'WHEREcustomers
.Id
= 3979 Customer Exists (0.2ms) SELECT 1 AS one FROMcustomers
WHERE (customers
.External_key
= 'CB001826' ANDcustomers
.Id
! = 3980 ) LIMIT 1 (0.1ms) UPDATEcustomers
SETvalidity
= 0 ,updated_at
= '2013- 11 -29 10:53:33 'WHEREcustomers
.Id
= 3980 Customer Exists (0.2ms) SELECT 1 AS one FROMcustomers
WHERE (customers
.External_key
= 'CB001822' ANDcustomers
.Id
! = 3981 ) LIMIT 1 (0.1ms) UPDATEcustomers
SETvalidity
= 0 ,updated_at
= '2013- 11 -29 10:53:33 'WHEREcustomers
.Id
= 3981 (2.2ms) SELECT COUNT (*) FROMcustomers
WHERE (external_key NOT IN ('12312 ')) (0.1ms) ROLLBACK
Like ROLLBACK appears at the end , but all clients will still remain valid : (
You must use a table in the database that supports transactions. For example InnoDB