For streaming video, we need to process the requested range of bytes for some browsers.
Solution 1: use send_file_with_range gem
A simple way could be the send_file method, fixed by the send_file_with_range gem .
Include Pearl in Gemfile
# Gemfile gem 'send_file_with_range'
and specify the range: true parameter for send_file :
def show video = Video.find(params[:id]) send_file video.full_path, type: "video/mp4", disposition: "inline", range: true end
The patch is quite short and noteworthy. But unfortunately, this did not work for me with Rails 4.2.
Solution 2: manually send_file patch
Inspired by a gem, manually expanding a controller is quite simple:
class VideosController < ApplicationController def show video = Video.find(params[:id]) send_file video.full_path, type: "video/mp4", disposition: "inline", range: true end private def send_file(path, options = {}) if options[:range] send_file_with_range(path, options) else super(path, options) end end def send_file_with_range(path, options = {}) if File.exist?(path) size = File.size(path) if !request.headers["Range"] status_code = 200 # 200 OK offset = 0 length = File.size(path) else status_code = 206 # 206 Partial Content bytes = Rack::Utils.byte_ranges(request.headers, size)[0] offset = bytes.begin length = bytes.end - bytes.begin end response.header["Accept-Ranges"] = "bytes" response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes send_data IO.binread(path, length, offset), options else raise ActionController::MissingFile, "Cannot read file #{path}." end end end
Further reading
Because, firstly, I did not know the difference between stream: true and range: true , I found this railscast useful:
http://railscasts.com/episodes/266-http-streaming