2015-11-07 2 views
2

У меня есть модель STI, в которой подклассы каждого из них используют разные проверки. По умолчанию в Rails будут выполняться проверки исходного типа во время выполнения, поэтому я пытаюсь использовать «становится» для принудительного подтверждения нового типа.Однонаправленное наследование и изменение типа не сохраняются

Мой код выглядит следующим образом:

payment_processor = PaymentProcessor.where(:account_id => self.id).first_or_initialize 

new_gateway = "PaymentProcessors::#{gateway_type.classify}".constantize 
payment_processor = payment_processor.becomes(new_gateway) 
payment_processor.type = new_gateway 

payment_processor.assign_attributes(attributes) 
payment_processor.save! 

Однако это не спасает, потому что MySQl генерируется во время сохранения ищет нового типа. Так, например, если мой первоначальный gateway_type является «AuthorizeNet» и я меняю на «PayPal», то MySQL является:

UPDATE `payment_processors` SET `type` = 'PaymentProcessors::PayPal', `updated_at` = '2015-11-07 11:53:53' WHERE `payment_processors`.`type` IN ('PaymentProcessors::PayPal') AND `payment_processors`.`id` = 232 

Но следует искать оригинальный тип, Auth.net как это:

UPDATE `payment_processors` SET `type` = 'PaymentProcessors::PayPal', `updated_at` = '2015-11-07 11:53:53' WHERE `payment_processors`.`type` IN ('PaymentProcessors::AuthorizeNet') AND `payment_processors`.`id` = 232 

Любые идеи о том, как пропустить предложение «where», чтобы просто обновить идентификатор платежного_процессора?

ответ

0

Я узнал, что STI терпит неудачу при проверке при попытке изменения типа. (Подробнее http://blog.arkency.com/2013/07/sti). Итак, я решил проблему, всегда создавая новый платежный_процессор, но восстанавливая старый, если проверка не выполняется. Это неэлегантно, но оно работает.

Скопируйте оригинал payment_processor затем удалить его:

original = self.payment_processor.destroy 
self.payment_processor.destroy 

Вместо передачи нового типа, мы удалим его из Params, но использовать new_gateway_type создать новый шлюз.

new_gateway_type = params[:payment_processor][:gateway_type] 
params[:payment_processor].delete(:gateway_type) 

Например, если новый шлюз «Paypal», мы constantize в new_gateway_type, чтобы создать новый объект, а затем обновить Params:

payment_processor = "PaymentProcessors::#{new_gateway_type}".constantize.new(:account_id => self.id) 
payment_processor.update_attributes(params[:payment_processor) 

Наконец, мы сохраняем новый шлюз , Если валидация не выполняется для этого нового_каталога, мы восстанавливаем старое путем согласования имени объектной модели и передачи новых атрибутов, кроме типа и идентификатора:

begin 
    payment_processor.save! 
rescue ActiveRecord::RecordInvalid => invalid 
    original.type.constantize.new(original.attributes.except("id", "type")).save 
end 
Смежные вопросы