Skip to content

Commit

Permalink
Update document storage library from ActiveSupport to CarrierWave for…
Browse files Browse the repository at this point in the history
… easier customization
  • Loading branch information
remomueller committed Aug 17, 2018
1 parent 6cf5c93 commit dace0fd
Show file tree
Hide file tree
Showing 34 changed files with 570 additions and 93 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ gem "pg", ">= 0.18", "< 2.0"
gem "autoprefixer-rails", "9.1.0"
gem "aws-sdk-s3", require: false
gem "bootstrap", "~> 4.1.3"
gem "carrierwave", "~> 1.2.3"
gem "devise", "~> 4.5.0"
gem "fog-aws"
gem "font-awesome-sass", "~> 5.2.0"
gem "haml", "~> 5.0.4"
gem "jquery-rails", "~> 4.3.3"
Expand Down
28 changes: 28 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ GEM
rack (>= 1.6.0)
rack-test (>= 0.6.3)
xpath (~> 3.1)
carrierwave (1.2.3)
activemodel (>= 4.0.0)
activesupport (>= 4.0.0)
mime-types (>= 1.16)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
coffee-rails (4.2.2)
Expand All @@ -97,17 +101,36 @@ GEM
warden (~> 1.2.3)
docile (1.3.1)
erubi (1.7.1)
excon (0.62.0)
execjs (2.7.0)
ffi (1.9.25)
fog-aws (3.0.0)
fog-core (~> 2.1)
fog-json (~> 1.1)
fog-xml (~> 0.1)
ipaddress (~> 0.8)
fog-core (2.1.0)
builder
excon (~> 0.58)
formatador (~> 0.2)
mime-types
fog-json (1.2.0)
fog-core
multi_json (~> 1.10)
fog-xml (0.1.3)
fog-core
nokogiri (>= 1.5.11, < 2.0.0)
font-awesome-sass (5.2.0)
sassc (>= 1.11)
formatador (0.2.5)
globalid (0.4.1)
activesupport (>= 4.2.0)
haml (5.0.4)
temple (>= 0.8.0)
tilt
i18n (1.1.0)
concurrent-ruby (~> 1.0)
ipaddress (0.8.3)
jbuilder (2.7.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
Expand Down Expand Up @@ -143,6 +166,9 @@ GEM
marcel (0.3.2)
mimemagic (~> 0.3.2)
method_source (0.9.0)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2018.0812)
mimemagic (0.3.2)
mini_mime (1.0.1)
mini_portile2 (2.3.0)
Expand Down Expand Up @@ -265,8 +291,10 @@ DEPENDENCIES
bootsnap (>= 1.1.0)
bootstrap (~> 4.1.3)
capybara (>= 2.15, < 4.0)
carrierwave (~> 1.2.3)
coffee-rails (~> 4.2)
devise (~> 4.5.0)
fog-aws
font-awesome-sass (~> 5.2.0)
haml (~> 5.0.4)
jbuilder (~> 2.5)
Expand Down
3 changes: 1 addition & 2 deletions app/assets/javascripts/objects/folders.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ $(document)

$this = $(this)
$uploadContainer = $("#folder-upload")
$percentbar = $("#upload-bar")
$percentbar = $("#folder-upload-bar")
$upload = $("#upload")
$percent = $("#percent")
$process = $("#process")
Expand Down Expand Up @@ -76,7 +76,6 @@ $(document)
$percentbar.addClass("upload-success")
$process.html("<i class=\"fa fa-check-square-o text-success\"/> <span class=\"text-muted\">Processing complete.</span><br>#{file_count} file#{plural} uploaded. Add more files?")
$uploadContainer.removeClass("upload-started")
setContinueButtonText("Continue")
).fail( (jqXHR, textStatus, errorThrown) ->
url = $this.data("fallback-url")
$percentbar.addClass("upload-failure")
Expand Down
9 changes: 9 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,13 @@ def empty_response_or_root_path(path = root_path)
format.pdf { redirect_to path }
end
end

# Expects an "Uploader" type class, ex: uploader = @project.logo
def send_file_if_present(uploader, *args)
if uploader.present?
send_file uploader.path, *args
else
head :ok
end
end
end
87 changes: 87 additions & 0 deletions app/controllers/documents_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# frozen_string_literal: true

# Allows documents to be downloaded.
class DocumentsController < ApplicationController
before_action :authenticate_user!
before_action :check_editor!, only: [:new, :create, :edit, :update, :destroy]
before_action :find_category_folder_document_or_redirect, only: [:download]
before_action :find_document_or_redirect, only: [
:show, :edit, :update, :destroy
]

layout "layouts/full_page_sidebar"

# # GET /docs
# def index
# @documents = Document.all
# end

# # GET /documents/1
# def show
# end

# GET /docs/:category/:folder/:filename
def download
params[:disposition] ||= "attachment" # "inline"
@document.increment! :download_count
if Rails.env.production?
redirect_to @document.file.url(query: { "response-content-disposition" => params[:disposition] })
else
send_file_if_present @document.file, disposition: params[:disposition]
end
end

# # GET /documents/new
# def new
# @document = Document.new
# end

# # GET /documents/1/edit
# def edit
# end

# # POST /documents
# def create
# @document = Document.new(document_params)
# if @document.save
# redirect_to @document, notice: "Document was successfully created."
# else
# render :new
# end
# end

# PATCH /documents/1
def update
if @document.update(document_params)
redirect_to category_folder_path(@document.folder.category, @document.folder), notice: "#{@document.filename} was successfully updated."
else
render :edit
end
end

# DELETE /documents/1
def destroy
@category = @document.folder.category
@folder = @document.folder
@document.destroy
redirect_to category_folder_path(@category, @folder), notice: 'Document was successfully deleted.'
end

private

def find_document_or_redirect
@document = Document.find_by(id: params[:id])
empty_response_or_root_path(documents_path) unless @document
end

def find_category_folder_document_or_redirect
@category = Category.find_by_param(params[:category])
@folder = @category.folders.find_by_param(params[:folder]) if @category
@document = @folder.documents.find_by(filename: params[:filename]) if @folder
empty_response_or_root_path(folders_path) unless @category && @folder && @document
end

def document_params
params.require(:document).permit(:featured)
end
end
28 changes: 19 additions & 9 deletions app/controllers/folders_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ class FoldersController < ApplicationController

# GET /docs
def index
@blobs = ActiveStorageBlob.latest_files
@documents = Document.latest_files
end

# # GET /docs/:category/:folder
# def show
# end
# GET /docs/:category/:folder
def show
@documents = docs_scope_order(@folder.documents).page(params[:page]).per(20)
end

# GET /docs/new
def new
Expand Down Expand Up @@ -61,18 +62,22 @@ def update
# POST /folders/1/attach-file
def attach_file
if params[:file].present?
@folder.files.attach(params[:file])
@folder.attach_file!(params[:file])
FilesJob.perform_later
redirect_to category_folder_path(@folder.category, @folder)
redirect_to category_folder_path(@folder.category, @folder, order: "latest")
else
redirect_to upload_category_folder_path(@folder.category, @folder), notice: "Choose a file to upload."
end
end

# POST /folders/1/attach-files
def attach_files
@folder.files.attach(params[:files])
params[:files].each do |file|
@folder.attach_file!(file)
end
FilesJob.perform_later
params[:order] = "latest"
@documents = docs_scope_order(@folder.documents).page(params[:page]).per(20)
render :show
end

Expand All @@ -86,12 +91,12 @@ def destroy

def find_category_and_folder_or_redirect
@category = Category.find_by_param(params[:category])
@folder = @category.folders.with_attached_files.find_by_param(params[:folder]) if @category
@folder = @category.folders.find_by_param(params[:folder]) if @category
empty_response_or_root_path(folders_path) unless @category && @folder
end

def find_folder_or_redirect
@folder = Folder.with_attached_files.find_by_param(params[:id])
@folder = Folder.find_by_param(params[:id])
empty_response_or_root_path(folders_path) unless @folder
end

Expand All @@ -106,4 +111,9 @@ def folder_params
:category_id, :name, :slug, :description, :archived
)
end

def docs_scope_order(scope)
@order = params[:order]
scope.order(Arel.sql(Document::ORDERS[params[:order]] || Document::DEFAULT_ORDER))
end
end
10 changes: 10 additions & 0 deletions app/helpers/documents_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

# Generate links to download documents.
module DocumentsHelper
# This intentionally builds the URL since ActionCable jobs and emails may not
# know the current request host.
def document_download_link(document)
"#{ENV["website_url"]}/docs/#{document.folder.category.to_param}/#{document.folder.to_param}/#{document.filename}"
end
end
4 changes: 2 additions & 2 deletions app/jobs/files_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ class FilesJob < ApplicationJob
queue_as :default

def perform
@blobs = ActiveStorageBlob.latest_files
@documents = Document.latest_files
ActionCable.server.broadcast(
"files_channel",
latest_uploads: AdminController.render(partial: "files/latest_uploads", locals: { blobs: @blobs })
latest_uploads: AdminController.render(partial: "files/latest_uploads", locals: { documents: @documents })
)
end
end
17 changes: 0 additions & 17 deletions app/models/active_storage_blob.rb

This file was deleted.

42 changes: 42 additions & 0 deletions app/models/document.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

# Represents a file uploaded to a folder. A document can be featured to be
# displayed on the dashboard, and tracks the number of times the file has been
# downloaded.
class Document < ApplicationRecord
# Uploaders
mount_uploader :file, GenericUploader

# Constants
ORDERS = {
"size" => "documents.byte_size",
"size desc" => "documents.byte_size desc",
"oldest" => "documents.created_at",
"latest" => "documents.created_at desc",
"name" => "LOWER(documents.filename)",
"name desc" => "LOWER(documents.filename) desc"
}
DEFAULT_ORDER = "LOWER(documents.filename)"

# Concerns
include PgSearch
multisearchable against: [:filename, :content_type]

# Validations
validates :filename, presence: true,
uniqueness: { case_sensitive: false, scope: [:folder_id] }

# Scopes
scope :latest_files, -> do
joins(:folder).merge(Folder.where(archived: false).joins(:category).merge(Category.sidebar)).order(created_at: :desc).limit(10)
end

# Relationships
belongs_to :folder, counter_cache: true

# Methods

def self.content_type(filename)
MIME::Types.type_for(filename).first.content_type
end
end
17 changes: 14 additions & 3 deletions app/models/folder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ class Folder < ApplicationRecord

# Validations
validates :name, presence: true,
uniqueness: { case_sensitive: false }
uniqueness: { case_sensitive: false, scope: [:category_id] }
validates :slug, format: { with: /\A[a-z][a-z0-9\-]*\Z/ },
exclusion: { in: %w(new edit create update destroy) },
uniqueness: true,
uniqueness: { case_sensitive: false, scope: [:category_id] },
allow_nil: true

# Relationships
belongs_to :category, counter_cache: true
has_many_attached :files
has_many :documents, dependent: :destroy

# Methods

def attach_file!(file)
documents.create(
file: file,
byte_size: file.size,
filename: file.original_filename,
content_type: Document.content_type(file.original_filename)
)
end
end
Loading

0 comments on commit dace0fd

Please sign in to comment.