adolfosrs
adolfosrs

Reputation: 9389

Asynchronously call controller action to return URL to use with image_tag

I currently have the following view thats is loading a bunch of images, one for each character inside an array. The problem is that get_character_thumbnail calls an api to get the images url and thats being done synchronously when the user requests the page data.

    <% @comic.characters.each do |character| %>
        <div class = "col-sm-6 col-md-3">
            <div class = "thumbnail">
                <%= image_tag(get_character_thumbnail(character)) %>
            </div>
            <div class = "caption">
                <p><%= character['name'] %></p>
            </div>
        </div>
    <% end %>

I want to enforce that each call to get_character_thumbnail(character) will be done asynchronously and the page doesn’t get stuck.

def get_character_thumbnail(character)
    response = HTTParty.get(character['resourceURI'], get_basic_api_options)
    response['data']['results'][0]['thumbnail']['path'] + '/portrait_large.jpg'
end

Since I’m pretty new to ruby on rails I’m struggling a little bit to setup an ajax call to do the trick. Does anyone have a suggestion or a link that could help me?

Upvotes: 3

Views: 429

Answers (2)

palash-kulkarni
palash-kulkarni

Reputation: 407

You should make an AJAX call and get all the images in response. Then store in Javascript object.

Reason for the Page Freeze -

  1. Because you might not be using closure concept of JavaScript. When we load/read multiple image files on browser, it occur because in the first iteration File-1 wasn't load and it jump to next iteration which sometimes causes not to load few random image files and freezes the browser.

You can check my Image Preview library (https://github.com/palash-kulkarni/image_uploader/blob/master/image-uploader-1.0.0.js). Its in progress, but i know it will definitely help you.

Link to Demo (https://github.com/palash-kulkarni/image_uploader/tree/master/Demo)

$.each(files, function (_, file) {
    if (image.types.test(file.type)) {
        that.displayPreview(file, categoryName, image);
        that.bindSingleDeleteEvent(categoryName, image);
    } else {
        that.clientMessage.display('#flash', image.failureMessage.invalidFileType);
    }
});
// Iterate object of images 
    reader = new FileReader();
    reader.onload = (function (img) {
        return function (event) {
            img.attr('src', event.target.result);
        };
    })(img);
    reader.readAsDataURL(imageFile);
// End Iterator

Upvotes: 1

max pleaner
max pleaner

Reputation: 26778

Your routes should always return a response immediately. Here's one approach in which you're writing a custom endpoint to serve a single character image. Your html page would load quickly, then you can set the img src attributes to point at your image route.

Here's some example code to clarify:

some html.erb template

<% @comic.characters.each do |character| %>
  <img src='/character_image/<%= character.id %>'>
<% end %>

a new route, get '/character_image/:id'

def character_image
  @char = Character.find(id: params[:id])
  img_path = "tmp/char_img_#{@char.id}.jpg"
  unless File.exists?(img_path)
    img_url = get_char_img(@char) # hit your API to get the url
    `wget #{img_url} -O #{img_path}`
  end
  send_file img_path, type: 'image/jpg', disposition: 'inline'
end

This code will cache the image to avoid duplicate API requests if, say, your html page were refreshed.

I'm using tmp/ here because it's a write-enabled location on Heroku (which blocks filesystem writes to other locations). On other environments (locally, for example), you could choose to save the images to public/, which Rails serves statically by default.

Upvotes: 1

Related Questions