правильное решение
Ну, «они» правы.Вы действительно должны сделать рендеринг в контроллере, но это справедливая игра, чтобы вызвать этот контроллер из модели!К счастью, AbstractController в Rails 3 делает это проще, чем я думал.Я сделал простой класс ActionPusher, работающий так же, как ActionMailer.Возможно, когда-нибудь я стану честолюбивым и сделаю это настоящим украшением, но это должно послужить хорошим началом для всех, кто на моем месте.
Я получил наибольшую помощь по этой ссылке: http://www.amberbit.com/blog/2011/12/27/render-views-and-partials-outside-controllers-in-rails-3/
в lib / action_pusher.rb
class ActionPusher < AbstractController::Base
include AbstractController::Rendering
include AbstractController::Helpers
include AbstractController::Translation
include AbstractController::AssetPaths
include Rails.application.routes.url_helpers
helper ApplicationHelper
self.view_paths = "app/views"
class Pushable
def initialize(channel, pushtext)
@channel = channel
@pushtext = pushtext
end
def push
Pusher[@channel].trigger('rjs_push', @pushtext )
end
end
end
в app / pushers / users_pusher.rb.Я предполагаю, что требование может пойти куда-нибудь более глобально?
require 'action_pusher'
class UsersPusher < ActionPusher
def initialize(user)
@user = user
end
def channel
@user.pusher_key
end
def add_notice(notice = nil)
@notice = notice
Pushable.new channel, render(template: 'users_pusher/add_notice')
end
end
Теперь в моей модели я могу просто сделать это:
after_commit :push_add_notice
private
def push_add_notice
UsersPusher.new(user).add_notice(self).push
end
и тогда вам понадобится частичное, например, приложение/views/users_pusher/add_notice.js.haml, который может быть простым:
alert('#{@notice.body}')
Я думаю, вам не нужно делать это с внутренним классом Pushable и вызовом .push в конце, но я хотел, чтобы это выглядело как ActiveMailer.У меня также есть метод pusher_key в моей пользовательской модели, чтобы создать канал для каждого пользователя - но это мой первый день с чем-то вроде Pusher, поэтому я не могу точно сказать, правильная ли это стратегия.Есть еще кое-что, что мне нужно, но этого достаточно для начала.
Удачи!
(это был мой первый черновой ответ, оставив его, потому что он может кому-то помочь)
У меня есть общий план работы решения.Например, в вашей модели:
after_create :push_new_message
private
def render_anywhere(partial, assigns = {})
view = ActionView::Base.new(ActionController::Base.view_paths, assigns)
view.extend ApplicationHelper
view.render(:partial => partial)
end
def push_new_message
pushstring = render_anywhere('notices/push_new_message', :message_text => self.body)
Pusher[user.pusher_key].trigger!('new_message', pushstring)
end
, которая определенно работает - шаблон рендерится и успешно получает eval () на стороне клиента.Я планирую почистить его, почти наверняка переместить render_any куда-нибудь куда более общее и, вероятно, попробовать что-то вроде этого
Я вижу, что для толчков потребуются свои собственные шаблоны, вызывающие общедоступныеи я могу попытаться собрать их всех в одном месте.Одна приятная небольшая проблема заключается в том, что я иногда использую controller_name в своих партиалах, например для подсветки пункта меню, но мне, очевидно, придется использовать другую тактику.Я предполагаю, что мне, возможно, придется что-то сделать, чтобы получить больше помощников, но я еще не добрался там.
Успех!Ура!Это должно ответить на ваш вопрос, и мой - я добавлю больше подробностей, если это покажется уместным позже.Удачи !!!!
оригинальный ответ от часа назад оставлен для ясности
У меня нет ответа, но этот своевременный вопрос заслуживает большего уточнения, и я надеюсьчтобы приблизиться к моему ответу, помогая спросить :)
Я столкнулся с той же проблемой.Чтобы объяснить это немного яснее, Pusher асинхронно отправляет контент в подключенный пользовательский браузер.Типичным вариантом использования может быть показ пользователю, у которого есть новое сообщение от другого пользователя.С помощью Pusher вы можете отправить сообщение в браузер получателя, чтобы они сразу получали уведомление, если вошли в систему. Для действительно отличной демонстрации того, что может сделать Pusher, посмотрите http://wordsquared.com/
Вы можете отправитьлюбые данные, которые вам нравятся, например, JSON-хеш для интерпретации того, как вам это нравится, но было бы очень удобно отправлять RJS, как и при любом другом вызове ajax, и eval () на стороне клиента.Таким образом, вы можете (например) визуализировать шаблон для вашей строки меню, обновить его полностью или просто счетчик новых сообщений, отображаемый для пользователя, используя все те же частичные значения, чтобы сохранить его в сухом виде.В принципе, вы можете визуализировать партиал из контроллера отправителя , но это также не имеет особого смысла, и может даже не быть запроса, он может быть запущен заданием cron, например,или другое событие, например, изменение цены акций.Контролеру отправителя просто не нужно знать об этом - мне нравится держать мои контроллеры на голодной диете;)
Это может звучать как нарушение MVC, но на самом деле это не так - и это действительно должно быть решено с помощью чего-то вроде ActionMailer, но с разделением помощников и частичных функций с остальной частью приложения.Я знаю, что в своем приложении я хотел бы отправить событие Pusher одновременно с вызовом ActionMailer (или вместо него).Я хочу отобразить произвольное частичное для пользователя B на основе события от пользователя A.
Эти ссылки могут указывать путь к решению:
Последний выглядит наиболее перспективным, предлагая этот дразнящий фрагмент:
def render_anywhere(partial, assigns)
view = ActionView::Base.new(Rails::Configuration.new.view_path, assigns)
ActionView::Base.helper_modules.each { |helper| view.extend helper }
view.extend ApplicationHelper
view.render(:partial => partial)
end
Как и эта ссылка предоставленадругим постером выше.
Я сообщу, если что-нибудь заработает
д-р: я тоже!