С Observers официально удален из Rails 4.0 мне интересно, что другие разработчики используют вместо них. (Кроме использования извлеченного драгоценного камня.) Хотя Обозреватели, несомненно, подвергались жестокому обращению и иногда могли легко стать громоздкими, было много вариантов использования, помимо простой очистки кеша, где они были полезны.
Возьмем, к примеру, приложение, которое должно отслеживать изменения в модели. Наблюдатель может легко отслеживать изменения в модели A и записывать эти изменения с помощью модели B в базу данных. Если вы хотите следить за изменениями в нескольких моделях, то один наблюдатель может справиться с этим.
В Rails 4 мне любопытно, какие стратегии используют другие разработчики вместо Observers для воссоздания этой функциональности.
Лично я склоняюсь к некой реализации «жирного контроллера», где эти изменения отслеживаются в методе создания / обновления / удаления контроллера каждой модели. Хотя он слегка раздувает поведение каждого контроллера, он помогает в удобочитаемости и понимании, поскольку весь код находится в одном месте. Недостатком является то, что теперь существует очень похожий код, разбросанный по нескольким контроллерам. Извлечение этого кода в вспомогательные методы является опцией, но вы все равно будете вызывать эти методы повсюду. Не конец света, но не совсем в духе "тощих контролеров".
Обратные вызовы ActiveRecord - это еще один возможный вариант, хотя лично мне он не нравится, так как, на мой взгляд, он слишком тесно связывает две разные модели.
Так что в Rails 4, мире без наблюдателей, если бы вам пришлось создавать новую запись после создания / обновления / уничтожения другой записи, какой шаблон проектирования вы бы использовали? Толстые контроллеры, обратные вызовы ActiveRecord или что-то еще целиком?
Спасибо.
источник
Ответы:
Посмотрите на проблемы
Создайте папку в каталоге моделей под названием проблемы. Добавьте туда модуль:
Затем включите это в модели, которые вы хотите запустить в after_save:
В зависимости от того, что вы делаете, это может сблизить вас без наблюдателей.
источник
Они в плагине сейчас.
Могу ли я также порекомендовать альтернативу, которая даст вам такие контроллеры, как:
источник
ActiveSupport::Notifications
ориентированы на инструментарий, а не на общий sub / pub.ActiveSupport::Notifications
?Notifications
много, но я бы сказал, чтоWisper
имеет более приятный API и такие функции, как «глобальные подписчики», «по префиксу» и «сопоставление событий», которыхNotifications
нет. В будущем выпускеWisper
также будет возможна асинхронная публикация через SideKiq / Resque / Celluloid. Также, потенциально, в будущих версиях Rails, API дляNotifications
может измениться, чтобы быть более сфокусированным на инструментах.Я предлагаю прочитать сообщение в блоге Джеймса Голика по адресу http://jamesgolick.com/2010/3/14/crazy-heretical-and-awesome-the-way-i-write-rails-apps.html (попытаться игнорировать нескромно звучит название).
Раньше это была вся "толстая модель, тощий контроллер". Тогда толстые модели стали гигантской головной болью, особенно во время тестирования. В последнее время толчок был для тощих моделей - идея заключалась в том, что каждый класс должен выполнять одну обязанность, а задача модели - сохранять ваши данные в базе данных. Так где же заканчивается вся моя сложная бизнес-логика? В классах бизнес-логики - классы, представляющие транзакции.
Этот подход может превратиться в болото (гиганство), когда логика начинает усложняться. Тем не менее, концепция разумна - вместо того, чтобы неявно вызывать вещи с помощью обратных вызовов или наблюдателей, которые трудно протестировать и отлаживать, явно запускайте вещи в классе, который накладывает логику поверх вашей модели.
источник
Использование обратных вызовов активных записей просто переворачивает зависимость вашей связи. Например, если у вас есть
modelA
иCacheObserver
стеллажи для наблюденияmodelA
3 стиля, вы можете удалитьCacheObserver
без проблем. Вместо этого, скажем,A
должен вручную вызыватьCacheObserver
после сохранения, что будет rails 4. Вы просто переместили свою зависимость, чтобы вы могли безопасно удалить,A
но неCacheObserver
.Теперь из своей башни из слоновой кости я предпочитаю, чтобы наблюдатель зависел от модели, которую он наблюдает. Я достаточно забочусь, чтобы загромождать мои контроллеры? Для меня ответ - нет.
Предположительно, вы задумывались над тем, почему вы хотите / нуждаетесь в наблюдателе, и, таким образом, создание модели, зависящей от ее наблюдателя, - не страшная трагедия.
У меня также есть (вполне обоснованное, я думаю) отвращение к любому виду наблюдателя, зависящему от действия диспетчера. Внезапно вы должны внедрить своего наблюдателя в любое действие контроллера (или другую модель), которое может обновить модель, которую вы хотите наблюдать. Если вы можете гарантировать, что ваше приложение будет когда-либо модифицировать экземпляры только с помощью действий контроллера создания / обновления, это даст вам больше возможностей, но я не буду исходить из предположения о приложении rails (рассмотрим вложенные формы, ассоциации обновления бизнес-логики модели и т. Д.).
источник
Wisper - отличное решение. Мое личное предпочтение обратных вызовов заключается в том, что они запускаются моделями, но события прослушиваются только при поступлении запроса, т.е. я не хочу, чтобы обратные вызовы запускались при настройке моделей в тестах и т. Д., Но я хочу их срабатывает всякий раз, когда задействованы контроллеры. Это очень легко настроить с помощью Wisper, потому что вы можете сказать, что он прослушивает только события внутри блока.
источник
В некоторых случаях я просто использую Active Support Instrumentation
источник
Моя альтернатива Rails 3 Observers - это ручная реализация, которая использует обратный вызов, определенный в модели, но при этом умудряется (как заявляет agmin в своем ответе выше) «перевернуть зависимость ... связь».
Мои объекты наследуются от базового класса, который предусматривает регистрацию наблюдателей:
(Конечно, в духе композиции над наследованием приведенный выше код можно поместить в модуль и смешать в каждой модели.)
Инициализатор регистрирует наблюдателей:
Затем каждая модель может определять свои собственные наблюдаемые события, помимо базовых обратных вызовов ActiveRecord. Например, моя модель User предоставляет 2 события:
Любой наблюдатель, который хочет получать уведомления об этих событиях, просто должен (1) зарегистрироваться в модели, которая представляет событие, и (2) иметь метод, имя которого соответствует событию. Как и следовало ожидать, несколько наблюдателей могут зарегистрироваться для одного и того же события, и (со ссылкой на 2-й абзац исходного вопроса) наблюдатель может наблюдать за событиями в нескольких моделях.
Классы наблюдателей NotificationSender и ProfilePictureCreator, представленные ниже, определяют методы для событий, представляемых различными моделями:
Одно предостережение заключается в том, что имена всех событий, представленных во всех моделях, должны быть уникальными.
источник
Я думаю, что проблема с устаревшими наблюдателями заключается не в том, что наблюдатели были плохими сами по себе, а в том, что они подвергались насилию.
Я бы не стал добавлять слишком много логики в ваши обратные вызовы или просто перемещать код, чтобы имитировать поведение наблюдателя, когда уже есть надежное решение этой проблемы - шаблон наблюдателя.
Если имеет смысл использовать наблюдателей, то обязательно используйте наблюдателей. Просто поймите, что вам нужно убедиться, что ваша логика наблюдателя соответствует практике кодирования звука, например, SOLID.
Камень наблюдателя доступен на rubygems, если вы хотите добавить его обратно в свой проект https://github.com/rails/rails-observers
см. эту короткую ветку, хотя и не полное всестороннее обсуждение, я думаю, что основной аргумент является действительным https://github.com/rails/rails-observers/issues/2
источник
Вы можете попробовать https://github.com/TiagoCardoso1983/association_observers . Он еще не тестировался для rails 4 (который еще не был запущен), и нуждается в некотором дополнительном сотрудничестве, но вы можете проверить, подходит ли он вам.
источник
Как насчет использования PORO вместо этого?
Логика заключается в том, что ваши «дополнительные действия по сохранению», скорее всего, будут бизнес-логикой. Это мне нравится держать отдельно от моделей AR (которые должны быть как можно более простыми) и контроллеров (которые надоедают правильно тестировать)
И просто назовите это так:
Вы даже можете расширить его, добавив дополнительные объекты действий после сохранения
И привести пример «статистов». Вы могли бы хотеть оживить их немного хотя:
Если вам нравится этот подход, я рекомендую прочитать сообщение в блоге Bryan Helmkamps 7 Patterns .
РЕДАКТИРОВАТЬ: я должен также упомянуть, что вышеупомянутое решение позволяет добавлять логику транзакции, когда это необходимо. Например, с ActiveRecord и поддерживаемой базой данных:
источник
Стоит отметить, что
Observable
модуль из стандартной библиотеки Ruby нельзя использовать в объектах, подобных активным записям, начиная с методов экземпляра,changed?
иchanged
будет конфликтовать с методами изActiveModel::Dirty
.Сообщение об ошибке для Rails 2.3.2
источник
У меня такой же пробьем! Я нахожу решение ActiveModel :: Dirty, чтобы вы могли отслеживать изменения вашей модели!
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
источник