In my model I have:
after_create :push_create
I push_create I need to render a view. I'm trying to do that like so:
def push_event(event_type) X["XXXXX-#{Rails.env}"].trigger(event_type, { :content => render( :partial =>"feeds/feed_item", :locals => { :feed_item => self }) } ) end
This angers rails as it doesn't like me rendering a view in the model but I need it there.
Error:
NoMethodError (undefined method `render' for #<WallFeed:0x1039be070>):
Suggestions? Should I render it somewhere else somehow? Or how can I render in the model to set content? Thanks
Rendering a Partial View You can render the partial view in the parent view using the HTML helper methods: @html. Partial() , @html. RenderPartial() , and @html. RenderAction() .
Ruby on Rails Views Partials Partials allow you to extract pieces of code from your templates to separate files and also reuse them throughout your templates. To create a partial, create a new file that begins with an underscore: _form.html.erb.
By default, if you use the :text option, the text is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the layout: true option.
There is an important difference between render and redirect_to: render will tell Rails what view it should use (with the same parameters you may have already sent) but redirect_to sends a new request to the browser.
Well, "they" are right. You really have to do the rendering in a controller - but it's fair game to call that controller from a model! Fortunately, AbstractController in Rails 3 makes it easier than I thought. I wound up making a simple ActionPusher class, working just like ActionMailer. Perhaps I'll get ambitious and make this a proper gem someday, but this should serve as a good start for anyone else in my shoes.
I got the most help from this link: http://www.amberbit.com/blog/2011/12/27/render-views-and-partials-outside-controllers-in-rails-3/
in 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
in app/pushers/users_pusher.rb. I guess the require could go somewhere more global?
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
Now in my model, I can just do this:
after_commit :push_add_notice private def push_add_notice UsersPusher.new(user).add_notice(self).push end
and then you'll want a partial, e.g. app/views/users_pusher/add_notice.js.haml, which could be as simple as:
alert('#{@notice.body}')
I guess you don't really need to do it with Pushable inner class and the .push call at the end, but I wanted to make it look like ActiveMailer. I also have a pusher_key method on my user model, to make a channel for each user - but this is my first day with anything like Pusher, so I can't say for sure if that's the right strategy. There's more to be fleshed out, but this is enough for me to get started.
Good luck!
I've got the general outline of a solution working. Like this, in your model:
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
that is definitely working - the template is rendering, and gets eval()'ed on the client side successfully. I'm planning to clean it up, almost certainly move render_anywhere somewhere more general, and probably try something like this
I can see that pushes will need their own templates, calling the generally available ones, and I may try to collect them all in one place. One nice little problem is that I sometimes use controller_name in my partials, like to light up a menu item, but I'll obviously have to take a different tactic there. I'm guessing I might have to do something to get more helpers available, but I haven't gotten there yet.
Success! Hooray! This should answer your question, and mine - I'll add more detail if it seems appropriate later. Good luck!!!!
I don't have an answer, but this timely question deserves more clarification, and I'm hoping to get closer to my answer by helping ask :)
I'm facing the same problem. To explain a little more clearly, Pusher asynchronously sends content to a connected user browser. A typical use case would be a showing the user they have a new message from another user. With Pusher, you can push a message to the receiver's browser, so they get an immediate notification if they are logged in. For a really great demo of what Pusher can do, check out http://wordsquared.com/
You can send any data you like, such as a JSON hash to interpret how you like it, but it would be very convenient to send RJS, just like with any other ajax call and eval() it on the client side. That way, you could (for example) render the template for your menu bar, updating it in its entirety, or just the new message count displayed to the user, using all the same partials to keep it bone-DRY. In principle, you could render the partial from the sender's controller, but that doesn't make much sense either, and there might not even be a request, it could be triggered by a cron job, for example, or some other event, like a stock price change. The sender controller just should not have to know about it - I like to keep my controllers on a starvation diet ;)
It might sound like a violation of MVC, but it's really not - and it really should be solved with something like ActionMailer, but sharing helpers and partials with the rest of the app. I know in my app, I'd like to send a Pusher event at the same time as (or instead of) an ActionMailer call. I want to render an arbitrary partial for user B based on an event from user A.
These links may point the way towards a solution:
The last one looks the most promising, offering up this tantalizing snippet:
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
As does this link provided by another poster above.
I'll report back if I get something working
tl;dr: me too!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With