2013-09-29 3 views
0

В моих рельсах приложение. У меня есть базовая модель - Пользователь. Пользователям доступно множество связанных объектов.Rails: Object destroy performance

Class User 
has_many :contents, dependent: destroy 
has_many :messages, dependent: destroy 
has_many :ratings, dependent: destroy 
has_many :groups, dependent: destroy 
... 
end 

Когда я хочу, чтобы удалить пользователя из моей системы (уничтожить объект пользователя), она занимает около минуты, чтобы уничтожить все связанные с ним объекты. Каков наилучший способ справиться с такими случаями?

Один из способов, который приходит мне на ум:

Уничтожая в delayed_job:

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

Есть ли лучший способ справиться с такими случаями?

+0

Один из вариантов заключается в том, чтобы сначала уничтожить пользователя и делегировать уничтожение связанных объектов в отложенное задание. – tihom

+1

Вы считали использование 'delete' вместо' destroy'?http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html – gabrielhilal

+1

@gabrielhilal да. но в случае удаления обратные вызовы наблюдателя не будут выполняться, и мне придется делать их также вручную. Подобно уничтожению пользователя, он уничтожает группы, которые, в свою очередь, должны обновлять счетчики и удалять действия в группе. Обработка их отдельно делает сложный бит кода. Но так ли это? –

ответ

0

: зависимые

контролирует, что происходит на соответствующий объект, когда уничтожается его владелец:

:destroy causes the associated object to also be destroyed 
:delete causes the associated object to be deleted directly from the database (so callbacks will not execute) 

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

Найти больше вариантов здесь: http://guides.rubyonrails.org/association_basics.html#options-for-has-one-dependent

+0

Спасибо @ Octopus-Paul. Но мои связанные объекты, в свою очередь, имеют собственные ассоциации. Как и в группе, есть много действий. поэтому разрушающая группа должна уничтожить свои ассоциации. –

+0

В этом случае вы не можете использовать: delete: D – cristian

2

Задача состоит в том, что, как вы, наверное, уже знаете, метод .destroy будет загружать каждый из детей объекты, а затем вызвать их .destroy методы.

Значение в том, что любые обратные вызовы для детей оцениваются перед выполнением окончательного уничтожения. Поэтому, если ребенку нужно прояснить что-либо в другом месте, он сделает это. Кроме того, если зависимые объекты выдают ошибку во время метода destroy, вся операция уничтожения будет откат, и вы не окажетесь на грани полумесяца.

.delete уничтожит объекты, не загружая их в память или не выполняя их обратные вызовы. Однако (очевидно) он не будет выполнять свои обратные вызовы.

Если вы хотите ускорить работу, вы можете либо просто сделать dependent: :delete, как предлагает Octopus-Paul. Это будет хорошо, но он не будет уничтожать иждивенцев на этих объектах, поэтому, например, если у групп были сообщения, связанные с ними, или, возможно, рейтинги имели связанные с ними комментарии, ни один из них не будет уничтожен.

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

Это создаст унаследованные проблемы в том, что кто-то, кто пишет код вниз по течению, не обязательно будет ожидать ваш метод, но вы можете судить об этом. Альтернатива (как вы говорите) - использовать флаг и выполнять работу асинхронно. Я бы предположил, что в будущем это будет иметь меньше рисков, но сегодня может быть более дорогостоящим.