# frozen_string_literal: true require 'filemagic' # Define un campo de archivo class MetadataFile < MetadataTemplate # Una ruta vacía a la imagen con una descripción vacía def default_value super || { 'path' => nil, 'description' => nil } end def empty? value == default_value end def validate super errors << I18n.t("metadata.#{type}.path_required") if path_missing? errors << I18n.t("metadata.#{type}.no_file_for_description") if no_file_for_description? errors.compact! errors.empty? end # Determina si necesitamos la imagen pero no la tenemos def path_missing? required && !path? end # Determina si el archivo ya fue subido def uploaded? value['path'].is_a?(String) && path? end # Determina si la ruta es opcional pero deja pasar si la ruta se # especifica def path_optional? !required && !path? end # Asociar la imagen subida al sitio y obtener la ruta def save return true unless changed? value['description'] = sanitize value['description'] value['path'] = nil unless path? return true if uploaded? return true if path_optional? return false unless hardlink.zero? # Modificar el valor actual value['path'] = relative_destination_path true end # Almacena el archivo en el sitio y lo devuelve # # @return ActiveStorage::Attachment def static_file return @static_file if @static_file return unless path? ActiveRecord::Base.connection_pool.with_connection do if uploaded? blob = ActiveStorage::Blob.find_by(key: key_from_path) @static_file ||= site.static_files.find_by(blob_id: blob.id) elsif site.static_files.attach(value['path']) @static_file ||= site.static_files.last end end end private def path? !value['path'].blank? end def filemagic @filemagic ||= FileMagic.new(FileMagic::MAGIC_MIME) end def path @path ||= Pathname.new value['path'] end # Obtiene la ruta absoluta del archivo # # @return [String|Nil] def file return unless path? if value['path'].is_a? ActionDispatch::Http::UploadedFile value['path'].tempfile.path else File.join site.path, value['path'] end end def key_from_path path.dirname.basename.to_s end # Hacemos un link duro para colocar el archivo dentro del repositorio # y no duplicar el espacio que ocupan. Esto requiere que ambos # directorios estén dentro del mismo punto de montaje. def hardlink FileUtils.mkdir_p File.dirname(destination_path) FileUtils.ln uploaded_path, destination_path end # Obtener la ruta al archivo # https://stackoverflow.com/a/53908358 def uploaded_relative_path ActiveStorage::Blob.service.path_for(static_file.key) end def uploaded_path Rails.root.join uploaded_relative_path end def relative_destination_path File.join('public', static_file.key, static_file.filename.to_s) end def destination_path File.join(site.path, relative_destination_path) end # No hay archivo pero se lo describió def no_file_for_description? value['description'].present? && value['path'].blank? end end