Topic: A few questions

Hello, I have a few questions related to a Rails app I am currently in the process of completing.

The first concerns caching. My app includes something of a picture gallery. Now I have two methods which I'll list here:

   def picture
   if Picture.exists?(params[:id])
    @picture = Picture.find(params[:id])
    send_data(@picture.data,
    :filename => @picture.name,
    :type => @picture.content_type,
    :disposition => "inline")
   else
   end
   
   end
   
   
   #In the photo list, when I click on this, display the photograph (resized with ems)
   def photo_display
    @picture = Picture.find(params[:id])
   end

The method photo_display has a view which displays the photo. The method picture actually sends the photo. At the top of my controller, I have:

  caches_page  :photo_display

Is this the right method to cache? I noticed that the initial display of my photos is quite fast, but then they seem to reload again so it's not really so fast considering I'm working on my local machine right now.

My next question is about Javascript and CSS files, can they also be cached? If so, how do I do this in my layout. Is it possible for the user to keep local copies of these files on their computer so they don't have to reload them everytime except when they change?

Thanks.

Re: A few questions

There are two different types of caching (actually more but to keep it simple): server-side and client-side. Because you are loading the page on your local it is a little hard to see the difference, but it still applies.

The "caches_page" method call is a server-side caching because it is taking the results of the action and storing in a separate file on the server so it doesn't have to access the database every time you call that action. Since you are only making one call to the database and you know the ID of the item you want, I don't think you will see much of a performance gain. With server-side caching, the data is still sent from the server to the client.

The other type of caching - client side - is probably what you are wanting. This is when the browser caches the image on the client's computer so it doesn't even have to ask the server for it. Unfortunately, as with all things client-side, you don't have nearly as much control over this. Most browser's cache images, css, and javascript files automatically. However, some browsers will remove the cache upon reloading which is probably why it seems like the image reloads again.

As I said, there are more types of caching, such as proxy cache, that happens between the server and the client. See this for more information on caching and how to control it:
http://www.mnot.net/cache_docs/

Railscasts - Free Ruby on Rails Screencasts

Re: A few questions

If pictures seem to reload without your intervention, there's something else at work. Because you are doing a send_data, that makes me suspect that you haven't told the browser what size image to expect in the <img> tag. Depending on which browser you are using, the rendering engine may be forced to re-render the page once it has enough data to determine the image size.

Re: A few questions

Thanks a lot. I didn't really understand the caching tutorial but it seems that my javascript files are being cached in the browser (i.e they are not being downloaded everytime a request is made which is good).
You are right, I haven't specified the image size, I am using CSS for that. I wonder if there is a way to fix this because my images look messed up in internet explorer.

Re: A few questions

IE, like almost every other browser, tries to cache what it can on the client side without compromising the intent of the Web page. CSS is not really supposed to change between requests, but I suppose if you are doing that you could add a unique query string to tell IE you've done so.

If you shut off caching in the browsers, pages load like molasses and bandwidth is gobbled up with redundant downloading of content (header images, css, javascripts, etc.).

Why not override the CSS style in your (X)HTML to specify the size?

Re: A few questions

Thanks, I've done that. I've also changed my picture method.
It now reads:

   def picture
   if Picture.exists?(params[:id])
   
    @picture = Picture.find(params[:id])
   
    minTime = Time.rfc2822(@request.env["HTTP_IF_MODIFIED_SINCE"]) rescue nil
    if minTime and @picture.updated_at <= minTime
        #use cached version
        render_text '', '304 Not Modified'
    else
    #send response headers
      @response.headers['Content-Description'] = @picture.comment
      @response.headers['Last-Modified'] = @picture.updated_at.httpdate   
    #send image
    send_data(@picture.data,
    :filename => @picture.name,
    :type => @picture.content_type,
    :disposition => "inline")
   
    end

This is like 5 times faster. Amazing stuff. Although it required that I add another column to my pictures database (updated_at).

Thanks.

Re: A few questions

Wow, that's really clever.  Thanks for posting all your code - I'm sure this'll come in handy for some of us later.