Topic: rendering a view outside of controller ?

Is there anyway I can render a view outside of a controller ?

I'm using BackgroundRB , and I'd like to use render_to_string in a worker to render some html that will update a facebook profile. These are perodic updates and so these must happen in a scheduled process rather than in real time from a controller.

The only other option I can think of is just to create an action that my worker calls with the appropriate values and ensure that the request is only allowed locally. I'd prefer not to do this as it may tie up some of my web server processes..

Re: rendering a view outside of controller ?

Just came across this old post searching for an answer to the same problem. Then I found this:
http://www.swombat.com/rails-rendering- … f-a-contro, which solved the problem for me, so just thought I'd leave the link here.
The trick boils down to something like this:

view = ActionView::Base.new(ActionController::Base.view_paths, {})
view.render(:file => "#{template_path}.html.erb", :locals => params)

where template_paths will be a path to a file relative to the views folder and params are whatever you need to pass to that view.

Re: rendering a view outside of controller ?

Ok this doesn't work for me.

What I'm trying to do is to call some jobs with the delayed_job plugin from the index controller. I followed the instructions of one of Ryan Bates great railscasts (http://railscasts.com/episodes/171-delayed-job) for to set up the delayed_job Plugin.
Those jobs later should run some test algorithms for every item in the index list (every database item). And then after finishing it should update the status of every item like "passed" or "failed".
Now for testing only I just called one job and within the job (after job is done) it should just render me a file, later I will make a for loop over all items that are listed and I want to pass different div IDs and those ID's after a job is finished should update the corresponding div on the index page (ajax and partial):

Ok, now this is the first attempt of mine with just trying to call a render of a file:

controller index action:

def index
Delayed::Job.enqueue(LanguageCheckJob.new('DIV_ID'))
end

Then in lib I create a new rb file. Here is the content:

class LanguageCheckJob
 
#initialize not needed in this first attempt
  def initialize(div_id)
    @div_id = div_id
  end

  def perform
    Delayed::Job.const_set('MAX_ATTEMPTS', 0)
    Delayed::Job.destroy_failed_jobs = false
    view = ActionView::Base.new(ActionController::Base.view_paths, {})
    view.render(:file => "backend/languages/test.html.erb")
  end
end


Now when I call the index page nothing happens and test.html.erb will not be rendered. There is no error thrown either.
Any ideas what I might do wrong here?
Is it even possible to redirect from a .rb file in /lib?

Re: rendering a view outside of controller ?

The following works fine for me:

view = ActionView::Base.new(ActionController::Base.view_paths, {})
view.render(:file => "index/test.html.haml")

But I'm not sure exactly what you were expecting. If you render the test.html.erb file in a delayed job, of course it won't get passed back to the view you see in the browser. It's simply returned as a string and unless you do anything with that string it will be quietly dropped from memory after the job is completed.

If you wanted to output the result to a file for example you could do this:

  html = view.render(:file => "backend/languages/test.html.erb")
  File.open('output.html', 'w').write( html )

Re: rendering a view outside of controller ?

marsvin wrote:

But I'm not sure exactly what you were expecting. If you render the test.html.erb file in a delayed job, of course it won't get passed back to the view you see in the browser. It's simply returned as a string and unless you do anything with that string it will be quietly dropped from memory after the job is completed.

Yes I thought it would really render that test.html.erb and show it in the browser.
So would you say this is impossible to do from a delayed job? Do you probably have an idea how I can achieve that?

Re: rendering a view outside of controller ?

Since the delayed job takes place separately from your request, and probably a little bit after the request completes, that is indeed impossible.

What you could do is take that result and store it somewhere in the database. Then in your view you could show "Still processing" as long as the result field is still empty and show the result after the delayed job finishes.

Re: rendering a view outside of controller ?

Yeah that would be a good 'alternative' solution you are right!

delayed_job already does indeed already save the jobs in the database by default. So I guess it would be no big deal to implement it in the way you suggested!

But, from my point of view, I would need something like an observer that may is started when I call the index action (in which I also call the jobs). Cause of course the index action (template) should be loaded 'fully' without waiting till every job has finished.
This observer method then should check in certain intervalls if a job is still running and read out the database entries after. And of course then call an ajax function that would replace the "Still processing" div. May delayed_job already offers something like that I really need to check that.

In the meanwhile: Does anyone have a clue where I could put such a function (controller, model..elsewhere?)
I'm pretty sure there is already such a solution somwhere. Maybe soemone could point me to that?

Re: rendering a view outside of controller ?

If you want to dynamically update the index (or show) view, you're right Ajax is the way to go. Just use the periodically_call_remote helper to make calls to the app every 30 seconds or something and let that remote call update the necessary fields if the database has changed.

Re: rendering a view outside of controller ?

I think you need something like

template = ERB.new(text, 0, "%<>")
@a = 'A'
@b = 'B' # @a and @b are used inside template
content = template.result(binding)

So check ERB class API.

Last edited by alexei.lexx (2009-08-06 14:29:15)