Forum: Ruby on Rails rendering images dynamically

5f57871af762854c5d9883ffd393c38d?d=identicon&s=25 candor (Guest)
on 2010-05-03 18:54
(Received via mailing list)
Hi,

I have a rails application where I respond to a request by fetching
image urls from various web api calls and need to display them as they
come available. I am able to display all the images once I get them
all, but that causes an unacceptable delay for my user.

One approach I am trying is, from my controller, set an @image
variable, and then pass in a block to the model that retrieves the
image urls. In the block, I call
     In the controller, I have:
  @query.load_images! do |image|
      @image = image
      render :update do |page|
        page.insert_html :bottom, 'images-div', :partial => 'images'
      end
    end

In my query model, I have:

def load_images! &block
   for(some_loop_that_gets_one_image_at_a_time) do
       image = get_next_image
       block.call(image)
   end
end

In the _images.html.erb, I have:

<%=image_tag @image.url %>

The problem is that with this approach, I get a DoubleRenderError, and
I think this is because render is being called multiple times in the
block call within the loop.

What is the best way to get the effect I need (to load images one at a
time as they become available)?

Thanks
Anand
5f57871af762854c5d9883ffd393c38d?d=identicon&s=25 candor (Guest)
on 2010-05-03 19:50
(Received via mailing list)
I tried a couple other approaches, but no success yet:

1. I reversed the blocks below - calling the load_images from within
render :update - that did give me the results, but all at once in the
end, not as the images show up.
2. I called redirect_to <controller/show_image?image_id=1 within the
inner loop in 1, and created a show_image.js.rjs file which calls
page.insert_html :bottom, 'images-div', :partial => 'image', but I get
an error 'ActionView::MissingTemplate (Missing template <mycontroller>/
show_image.erb in view path app/views) I dont really understand why
this is happening - shouldnt it pick the rjs template if present
instead of the erb?

What I really want is to leverage http to parallelize the retrieval
and rendering of images. How do I do that?

Thanks
Anand
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2010-05-03 20:04
(Received via mailing list)
On May 3, 2010, at 1:49 PM, candor wrote:

> show_image.erb in view path app/views) I dont really understand why
> this is happening - shouldnt it pick the rjs template if present
> instead of the erb?
>
> What I really want is to leverage http to parallelize the retrieval
> and rendering of images. How do I do that?
>
> Thanks
> Anand

<img src="/controller/show_image?image_id=1" />

Then the browser will ask for that URL and you can respond with a
send_file or send_data (rather than a render or redirect).

-Rob

>> all, but that causes an unacceptable delay for my user.
>>     end
>> In the _images.html.erb, I have:
>> time as they become available)?
>> .
> For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en
> .
>

Rob Biedenharn    http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
5f57871af762854c5d9883ffd393c38d?d=identicon&s=25 Anand Ramanathan (Guest)
on 2010-05-03 21:21
(Received via mailing list)
Thanks, Rob

I tried a variant of your suggestion, where I redirect instead of
send_data
(since in my case, the images are coming from elsewhere)  - I still have
the
same issue (that the images are all rendered once in the end,not one by
one
as they are retrieved). Here is the current code:

main controller:

def show_images
   render :update do |page|
      page.replace_html 'images-div', ''
      @query.load_images! do |image|
       @image = image
       page.insert_html :bottom, 'images-div', :partial => 'image'
unless
@image.id.nil?
      end
    end
end

query model:

def load_images!
...
  for(some_loop_that_gets_one_image_at_a_time)
    block.call(image)
  end
...
end

_image.html.erb

<%=image_tag('/images/%s/show' % @image.id)%>

images_controller:

def show
    @image = Image.find(params[:id])
    redirect_to @image.url
  end

Thanks
Anand
On Mon, May 3, 2010 at 11:01 AM, Rob Biedenharn
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2010-05-03 21:40
(Received via mailing list)
On May 3, 2010, at 3:20 PM, Anand Ramanathan wrote:

> def show_images
> query model:
>
> <%=image_tag('/images/%s/show' % @image.id)%>

Right here, just let the browser leverage HTTP to get the parallelized
behavior you seek:

<%= image_tag @image.url %>

or even:

<img src="<%= @image.url %>" />

If you're doing a redirect, the url isn't going to be "hidden" anyway.

You're never going to get the images to show up "one at a time" unless
you stop doing all the work in one request.

-Rob
5f57871af762854c5d9883ffd393c38d?d=identicon&s=25 Anand Ramanathan (Guest)
on 2010-05-03 22:58
(Received via mailing list)
Thanks again, Rob

I made the change you suggested (I realize that the additional action
call
and redirect are redundant), and I still get the images rendering all at
once in the end. I am a newbie to rails, so dont understand fully how it
works, but here are my current confusions :

1. Does all the javascript of a "render :update" block get emitted in
one
go, or does each page.do_this call in that get sent back independently?
If
the former, then I understand that this approach wont work for me. If
there
is some way to achieve the latter, then each page.insert_html could be
sent
back independently, and each image could be rendered in parallel. Is
there
any way to achieve the latter, through some setting, perhaps?

2. Rob said: You're never going to get the images to show up "one at a
time"
> unless you stop doing all the work in one request.
>
Does that mean that I cannot call multiple page. do_something calls in
parallel within the response chain of one request? All I want is to send
an
async request "get_images" and receive a callback "got_one_image" each
time
an image is ready...


Thanks
Anand

On Mon, May 3, 2010 at 12:39 PM, Rob Biedenharn
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2010-05-03 23:13
(Received via mailing list)
On May 3, 2010, at 4:56 PM, Anand Ramanathan wrote:

> Thanks again, Rob
>
> I made the change you suggested (I realize that the additional
> action call and redirect are redundant), and I still get the images
> rendering all at once in the end. I am a newbie to rails, so dont
> understand fully how it works, but here are my current confusions :
>
> 1. Does all the javascript of a "render :update" block get emitted
> in one go, or does each page.do_this call in that get sent back
> independently?

You get a single response to each request.

> to send an async request "get_images" and receive a callback
> "got_one_image" each time an image is ready...
>
> Thanks
> Anand

Yup! Now, if you really want to "chain" the requests, you could
probably do some AJAX call so that the JavaScript that is sent back
does one image replace and then immediately kicks off the next
request.  Alternatively, if you really only care about the appearance
of a sequential load, do the sequential "reveals" with JavaScript (via
scriptaculous or jQuery-effects).

Of course, it might make a big difference if you're talking about 4-5
images or 400-500 images, too. Your
"some_loop_that_gets_one_image_at_a_time" is rather vague after all.

-Rob

>> once in the end,not one by one as they are retrieved). Here is the
>> unless @image.id.nil?
>>   end
> <%= image_tag @image.url %>
> -Rob
>> Thanks
>> 2. I called redirect_to <controller/show_image?image_id=1 within the
>> and rendering of images. How do I do that?
>>
>> come available. I am able to display all the images once I get them
>>      end
>>
>> at a
> --
> --
> You received this message because you are subscribed to the Google
> Groups "Ruby on Rails: Talk" group.
> To post to this group, send email to rubyonrails-
> talk@googlegroups.com.
> To unsubscribe from this group, send email to 
rubyonrails-talk+unsubscribe@googlegroups.com
> .
> For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en
> .

Rob Biedenharn    http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
+1 513-295-4739
Skype:  rob.biedenharn
5f57871af762854c5d9883ffd393c38d?d=identicon&s=25 Anand Ramanathan (Guest)
on 2010-05-04 06:41
(Received via mailing list)
Thanks, Rob

I finally got it working by using periodically_call_remote in
conjunction
with the spawn plugin which runs the long process in parallel.

Thanks for your help!
Anand

On Mon, May 3, 2010 at 2:12 PM, Rob Biedenharn
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.