0.0
No commit activity in last 3 years
No release in over 3 years
A rack middleware and/or endpoint to serve up files from MogileFS
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0

Runtime

>= 1.1.0
 Project Readme

rack-mogilefs

If you are using Nginx you'll probably want to serve MogileFS files with the MogileFS Module, but if you need a quick way to serve them out of a Rack app, this should help.

Getting Started:

First install the gem:

gem install rack-mogilefs

There are a variety of ways to use it:

Rails 3:

# (config/routes.rb)
match "/assets/*path" => Rack::MogileFS::Endpoint.new

Rails 2:

# (app/metal/mogilefs_metal.rb)
class MogilefsMetal
  def self.call(env)
    if env["PATH_INFO"] =~ %r{^/assets/*}
      Rack::MogileFS::Endpoint.new.call(env)
    else
      [ 404, { "Content-Type" => "text/html" }, ["Not Found"] ]
    end
  end
end

Rack middleware

# (config.ru)
use Rack::MogileFS, :path => %r{^/assets/*}

Paperclip Integration

If you are using MogileFS as a backend for Paperclip you'll want to do one of two things.

a) Set your mogilefs route to /system/*

match "/system/*path" => Rack::MogileFS::Endpoint.new

b) Change paperclip's url to match your mogilefs route, if /assets*, then:

// Rails.root/config/initializers/paperclip_mogile_url.rb
Paperclip::Attachment.default_options.merge!(:url => "/assets/:attachment/:id/:style/:filename")

File Lookup

Rack::MogileFS uses the request path (PATH_INFO) for the MogileFS key. The content type of the file is detected by the extension, using the mime-types gem.

If you want to customize the mapping of the PATH_INFO string to a MogileFS key you can provide a mapper proc (or anything that responds to call) like this:

# map '/assets/filename.gif' to the mogilefs key 'filename.gif'
# Rack::MogileFS and Rack::MogileFS::Endpoint take the same options
use Rack::MogileFS,
  :path   => %r{^/assets/*},
  :mapper => lambda { |path| path.sub('/assets/', '') }

Configuration

Endpoint configuration

Here is an example of a fully customized Rack::MogileFS::Endpoint. Read the source for more documentation.

Using the expires option is recommended, other options probably aren't needed.

Rack::MogileFS::Endpoint.new(
  :default_content_type => "image/png",
  :expires              => 1.month, # or pass a proc...
  :expires              => lambda { |path, ext, mime| if mime == "images/png" ? 600 : 300 },
  :client               => MyMogileClient.new,
  :mapper               => lambda { |path| "/namespace/" + path },
  :strategy             => :reproxy,
  :debug                => false
)

Here is how I usually use it in development:

Rack::MogileFS::Endpoint.new(:expires => 1.month, :debug => true)

And production:

Rack::MogileFS::Endpoint.new(:expires => 1.month)

Client Configuration

If Rack::MogileFS detects it is inside a Rails app, it will look for a yaml config in config/mogilefs.yml that looks like this:

development:
  connection:
    domain: "development.myapp.com"
    hosts:
      - 127.0.0.1:7001
      - 127.0.0.1:7001
  class: "file"
staging:
  ...

and initialize a MogileFS client like this:

config = YAML.load_file( Rails.root.join("config/mogilefs.yml") )[Rails.env]
MogileFS::MogileFS.new( config["connection"].symbolize_keys )

You can override this by passing in a MogileFS client of your own:

Rack::MogileFS::Endpoint.new :client => MyMogileFSClient.new

Caveats ( serving files vs reproxying )

Serving files through Ruby can be slow. Rack::MogileFS will read the entire file into memory before sending it downstream. If you have varnish/squid/a CDN sitting in front of rails then this isn't so problematic.

The preferred method is to set an X-Reproxy-Url header from your app and let the web server serve the file instead of Rack::MogileFS. For Nginx, you could have a config like this:

location /reproxy {
    internal;
    set $reproxy $upstream_http_x_reproxy_url;
    proxy_pass $reproxy;
    proxy_hide_header Content-Type;
}

For Apache, there is mod_reproxy

Rack::MogileFS will use this method if you pass a strategy option of :reproxy

use Rack::MogileFS, :strategy => :reproxy

Rack::MogileFS will look up the internal urls for the file, and set two headers to reproxy the request:

X-Accel-Redirect: /reproxy
X-Reproxy-Url: http://internal.ip/path/to/mogile/file.fid

You'll have to make sure your web server knows how to handle this request.