Skip to content

Instantly share code, notes, and snippets.

@darrenboyd
Created February 17, 2024 22:32
Show Gist options
  • Save darrenboyd/6f77557ad799913c44aa3b3984b38089 to your computer and use it in GitHub Desktop.
Save darrenboyd/6f77557ad799913c44aa3b3984b38089 to your computer and use it in GitHub Desktop.
Example of overriding ActiveStorage controllers for authentication
# frozen_string_literal: true
class Storage::DirectUploadsController < ActiveStorage::DirectUploadsController
include AuthenticationSupport
include Pundit::Authorization
before_action :authenticate_user!
before_action :require_admin
protected
def require_admin
unless current_user.is_admin?
raise Pundit::NotAuthorizedError
end
end
end
# frozen_string_literal: true
class Storage::Blobs::RedirectController < ActiveStorage::Blobs::RedirectController
include AuthenticationSupport
include Pundit::Authorization
# maybe, or maybe not, depending on the context of the blob?
before_action :authenticate_user!
def show
# grab whatever relationship is important from the blob...
content = @blob.attachments.first.record.content
unless current_user.is_admin?
authorize # ... something, depending on your models and context
end
super
end
end
Rails.application.routes.draw do
# ... all your routes...
# ==============================================
# ============= ActiveStorage ==================
# ==============================================
# Largely copied these out of the active-storage source,
# to point them at our own set of controllers when needed.
scope ActiveStorage.routes_prefix do
get "/blobs/redirect/:signed_id/*filename" => "storage/blobs/redirect#show", as: :rails_service_blob
get "/blobs/:signed_id/*filename" => "storage/blobs/redirect#show"
# get "/representations/redirect/:signed_blob_id/:variation_key/*filename" => "active_storage/representations/redirect#show", as: :rails_blob_representation
# get "/representations/:signed_blob_id/:variation_key/*filename" => "active_storage/representations/redirect#show"
# These two can stay, as the disk service is only used in development
get "/disk/:encoded_key/*filename" => "active_storage/disk#show", as: :rails_disk_service
put "/disk/:encoded_token" => "active_storage/disk#update", as: :update_rails_disk_service
post "/direct_uploads" => "storage/direct_uploads#create", as: :rails_direct_uploads
end
# direct :rails_representation do |representation, options|
# route_for(ActiveStorage.resolve_model_to_route, representation, options)
# end
resolve("ActiveStorage::Variant") { |variant, options| route_for(ActiveStorage.resolve_model_to_route, variant, options) }
resolve("ActiveStorage::VariantWithRecord") { |variant, options| route_for(ActiveStorage.resolve_model_to_route, variant, options) }
resolve("ActiveStorage::Preview") { |preview, options| route_for(ActiveStorage.resolve_model_to_route, preview, options) }
direct :rails_blob do |blob, options|
route_for(ActiveStorage.resolve_model_to_route, blob, options)
end
resolve("ActiveStorage::Blob") { |blob, options| route_for(ActiveStorage.resolve_model_to_route, blob, options) }
resolve("ActiveStorage::Attachment") { |attachment, options| route_for(ActiveStorage.resolve_model_to_route, attachment.blob, options) }
direct :rails_storage_redirect do |model, options|
expires_in = options.delete(:expires_in) { ActiveStorage.urls_expire_in }
expires_at = options.delete(:expires_at)
if model.respond_to?(:signed_id)
route_for(
:rails_service_blob,
model.signed_id(expires_in: expires_in, expires_at: expires_at),
model.filename,
options
)
else
signed_blob_id = model.blob.signed_id(expires_in: expires_in, expires_at: expires_at)
variation_key = model.variation.key
filename = model.blob.filename
route_for(
:rails_blob_representation,
signed_blob_id,
variation_key,
filename,
options
)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment