Last active
July 28, 2016 22:03
-
-
Save bdevel/eb186a2d063bfdeb6814a0e6248f9a89 to your computer and use it in GitHub Desktop.
Rails controller for storing and fetching files from Postgres Large Objects (LO)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'digest' | |
class Api::V2::FileStorageController < ApplicationController | |
skip_before_filter :authorize, :only => [:save, :serve] | |
before_filter :authorize_admin_api_token, :only => [:save] | |
def save | |
if params[:contents].is_a?(ActionDispatch::Http::UploadedFile) | |
params[:contents].close(false) # close and don't delete so we can import it | |
tmp_file = params[:contents] | |
else | |
raise "No upload to process." | |
end | |
uploaded_file = nil | |
sha = Digest::SHA512.file tmp_file.path | |
sha.hexdigest | |
UploadedFile.connection.transaction do | |
uploaded_file = UploadedFile.find_or_initialize_by(filename: params[:filename]) | |
if uploaded_file && uploaded_file.file_oid | |
# Remove old file | |
UploadedFile.connection.execute "SELECT LO_UNLINK('#{uploaded_file.file_oid}')" | |
end | |
res = UploadedFile.connection.execute "SELECT LO_IMPORT('#{tmp_file.path}') AS file_oid" | |
uploaded_file.file_oid = res[0]["file_oid"].to_i | |
uploaded_file.checksum = sha.hexdigest | |
uploaded_file.headers = params[:headers] | |
uploaded_file.permissions = params[:permissions] || 'protected' | |
uploaded_file.save! | |
end | |
File.unlink tmp_file.path | |
render :json => uploaded_file.to_json, status: :created | |
end | |
def serve | |
file = UploadedFile.find_by(filename: params[:filename]) | |
if file.nil? | |
render :text => "File not found.", content_type: "text/plain", status: 404 | |
return | |
end | |
if !file.public? | |
authorize() | |
return unless signed_in? | |
end | |
# Make sure if file changes that it will bust the cache | |
tmp_path = "#{Rails.root}/tmp/uploaded_file_#{file.file_oid}_#{file.updated_at.to_i}" | |
if !File.exist?(tmp_path) | |
UploadedFile.connection.execute "SELECT LO_EXPORT(#{file.file_oid}, '#{tmp_path}')" | |
end | |
send_file(tmp_path, type: file.mime_type, disposition: nil) | |
file.headers.each do |k, v| | |
response.headers[k] = v | |
end unless file.headers.nil? | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UploadedFile < ActiveRecord::Base | |
store_accessor :headers | |
def extension | |
filename.match(/\.[a-zA-Z]+$/).to_a.first.to_s.downcase | |
end | |
def mime_type | |
Rack::Mime.mime_type(extension) | |
end | |
def as_json(*args) | |
json = super(*args) | |
json["mimeType"] = mime_type | |
json | |
end | |
def public? | |
permissions == 'public' | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CreateUploadedFiles < ActiveRecord::Migration | |
def change | |
create_table :uploaded_files do |t| | |
t.string :filename | |
t.string :checksum | |
t.string :permissions | |
t.integer :file_oid | |
t.hstore :headers | |
t.timestamps | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment