2018-11-20 22:27:40 +01:00
|
|
|
|
# references:
|
|
|
|
|
# https://evilmartians.com/chronicles/active-storage-meets-graphql-pt-2-exposing-attachment-urls
|
|
|
|
|
|
|
|
|
|
module Extensions
|
|
|
|
|
class Attachment < GraphQL::Schema::FieldExtension
|
2022-11-24 13:16:37 +01:00
|
|
|
|
attr_reader :attachment_assoc, :root
|
2018-11-20 22:27:40 +01:00
|
|
|
|
|
|
|
|
|
def apply
|
2022-11-07 14:24:28 +01:00
|
|
|
|
# Here we try to define the ActiveRecord association name:
|
2018-11-20 22:27:40 +01:00
|
|
|
|
# - it could be set explicitly via extension options
|
|
|
|
|
# - or we imply that is the same as the field name w/o "_url"
|
|
|
|
|
# suffix (e.g., "avatar_url" => "avatar")
|
2022-11-07 14:24:28 +01:00
|
|
|
|
@attachment_assoc = if options.key?(:attachment)
|
|
|
|
|
"#{options[:attachment]}_attachment"
|
|
|
|
|
elsif options.key?(:attachments)
|
|
|
|
|
"#{options[:attachments]}_attachments"
|
|
|
|
|
else
|
|
|
|
|
attachment = field.original_name.to_s.sub(/_url$/, "")
|
|
|
|
|
"#{attachment}_attachment"
|
|
|
|
|
end
|
2022-11-24 13:16:37 +01:00
|
|
|
|
@root = options&.dig(:root) || :object
|
2018-11-20 22:27:40 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# This method resolves (as it states) the field itself
|
|
|
|
|
# (it's the same as defining a method within a type)
|
|
|
|
|
def resolve(object:, **_rest)
|
2023-01-18 18:05:59 +01:00
|
|
|
|
root_instance = object.public_send(root)
|
2018-11-20 22:27:40 +01:00
|
|
|
|
Loaders::Association.for(
|
2023-01-18 18:05:59 +01:00
|
|
|
|
root_instance.class,
|
2018-11-20 22:27:40 +01:00
|
|
|
|
attachment_assoc => :blob
|
2023-01-18 18:05:59 +01:00
|
|
|
|
).load(root_instance)
|
2018-11-20 22:27:40 +01:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# This method is called if the result of the `resolve`
|
|
|
|
|
# is a lazy value (e.g., a Promise – like in our case)
|
|
|
|
|
def after_resolve(value:, **_rest)
|
2022-11-07 14:24:28 +01:00
|
|
|
|
if value.respond_to?(:map)
|
|
|
|
|
attachments = value.map { after_resolve_attachment(_1) }
|
|
|
|
|
|
2022-12-06 13:34:39 +01:00
|
|
|
|
if options[:as] == :single
|
2022-11-07 14:24:28 +01:00
|
|
|
|
attachments.first
|
|
|
|
|
else
|
|
|
|
|
attachments
|
|
|
|
|
end
|
|
|
|
|
else
|
2022-12-06 13:34:39 +01:00
|
|
|
|
attachment = after_resolve_attachment(value)
|
|
|
|
|
if options[:as] == :multiple
|
|
|
|
|
[attachment]
|
|
|
|
|
else
|
|
|
|
|
attachment
|
|
|
|
|
end
|
2022-11-07 14:24:28 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
|
|
def after_resolve_attachment(attachment)
|
|
|
|
|
return unless attachment
|
|
|
|
|
|
|
|
|
|
if attachment.virus_scanner.safe? || attachment.virus_scanner.pending?
|
|
|
|
|
attachment
|
2019-12-11 12:24:50 +01:00
|
|
|
|
end
|
2018-11-20 22:27:40 +01:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|