Let say you want to be able to render dynamic logo on your page. The logo will be rendered depending on who will be logged in. Of course you can do:

# app/helpers/application_helper.rb
def logo_image
  if true  # if admin
    'some other image'
# app/views/layouts/application_layout.html.haml
= image_tag logo_image

… but what if you want to hide remote / cloud URLs on your page (S3 Amazon people in da house ?)

So what we are looking for is dynamic render from some kind of Branding Controller:

# config/routes.rb
get 'logo', to: "branding#logo"
-# app/views/layouts/application_layout.html.haml
= image_tag 'logo.png'

for Local stored files

class BrandingController < ApplicationController
  def logo
    send_file 'public/rails.png', type: 'image/png', disposition: 'inline'

for Remote stored files

(according to http://api.rubyonrails.org/classes/ActionController/DataStreaming.html)

class BrandingController < ApplicationController
  def logo
    data = open("http://www.gravatar.com/avatar/c2713a4959692f16d27d2553fb06cc4b.png?r=x&s=170") 
    send_data data, type: image.content_type, disposition: 'inline'

According to this StackOverflow answer, more arguments may be nedded:

send_data data.read, filename: "#{type}.png", type: data.content_type, disposition: 'inline',  stream: 'true', buffer_size: '4096'

…but it seems that was ment for older Rails versions because Rails 4 doesn’t do anything with those extra options for streaming Rails Data Streaming.

Also you don’t need filename option as you are rendering file in browser (the disposition: 'inline' option) not telling browser to download the file.

If you want do tell browser to download file, syntax should be something like:

send_data generate_tgz('dir'), filename: 'dir.tgz'

CarrierWave gem

One may ask if specifying MimeType is important. Modern browsers will automatically determine what MimeType they are dealing with from the first few bytes of file. Well if you you want really easy functionality for modern Browsers only you may ignore passing of mime type.

What I found out interesting was that when I didn’t specify content type in send_data & send_file newer browsers were rendering images correctly. However when I visited controller path, browser was trying to download the image (you know that pop up thing if you want to save file). This happened despite the disposition: 'inline' option.

It’s obvious that Mime Type is important.

If you want to be lazy you can at least pass type: 'image/png' for all send files (I’m not recommending this, in fact it’s a terrible idea !!!)

Another way is to determine mime type from file name

MIME::Types.type_for("filename.gif").first.content_type # => "image/gif"

But this it’s just fetching mime type by extension.

Rather store mime type in your database


Keywords: Rails 4, Ruby 2, Data Streaming, CarrierWave, OpenURI, send image