with rails multiple files aws active ruby-on-rails ruby ruby-on-rails-3 filenames carrierwave

ruby-on-rails - multiple - ruby on rails active storage



CarrierWave: crea el mismo nombre de archivo Ășnico para todos los archivos versionados (2)

Puedes hacer algo como esto en tu archivo de uploader , y también funcionará para archivos versionados (es decir, si tienes una imagen y luego creas otras 3 versiones en miniatura del mismo archivo, todas tendrán el mismo nombre, solo que con información de tamaño). añadido en el nombre):

# Set the filename for versioned files def filename random_token = Digest::SHA2.hexdigest("#{Time.now.utc}--#{model.id.to_s}").first(20) ivar = "@#{mounted_as}_secure_token" token = model.instance_variable_get(ivar) token ||= model.instance_variable_set(ivar, random_token) "#{model.id}_#{token}.jpg" if original_filename end

Esto creará un nombre de archivo como este, por ejemplo: 76_a9snx8b81js8kx81kx92.jpg donde 76 es el id del modelo y el otro bit es un hex de SHA aleatorio.

Antes de entrar en detalles, iré directo al punto: ¿alguien ha descubierto una manera de hacer que Carrierwave guarde los archivos con sus nombres como una marca de tiempo o cualquier cadena arbitraria que sea única para cada archivo?

Por defecto, Carrierwave guarda cada archivo y sus versiones alternativas en su propio directorio (llamado así por el número de identificación del modelo). No soy un fan de esto porque en lugar de un directorio con 1,000, por el simple hecho de usar un número grande y redondo, los archivos (en mi caso, las imágenes) contienen un directorio con 1,000 subdirectorios, cada uno con uno o dos archivos. Puaj

Ahora, cuando reemplaza el método store_dir su Uploader para ser algo como lo siguiente:

def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}" end

Terminas con el comportamiento exacto que quiero. Todos los archivos (imágenes) van en una carpeta grande y feliz. No más subcarpetas que se queden cuando el objeto se elimina.

Solo hay un problema. Colisiones de archivos. Si subes delicious_cake.jpg dos veces, la segunda sobrescribirá a la primera, incluso si son dos imágenes diferentes de una deliciosa torta. Eso es claramente por qué el método store_dir tiene el extra /#{model.id} añadido al final del valor que devuelve.

¿Entonces lo que hay que hacer? Después de leer un poco, descubrí que en el archivo de carga generado hay una solución aparente comentada.

# Override the filename of the uploaded files: # Avoid using model.id or version_name here, see uploader/store.rb for details. # def filename # "something.jpg" if original_filename # end

Después de un poco de búsqueda encontré a alguien que había hecho lo siguiente

def filename @name ||= "#{secure_token}.#{file.extension}" if original_filename end

Esto me hizo pensar, ¿por qué no hacer esto?

def filename @name ||= "#{(Time.now.to_i.to_s + Time.now.usec.to_s).ljust(16, ''0'')}#{File.extname(original_filename)}" end

Fue entonces cuando las cosas se rompieron horriblemente. El problema con esto es que aparentemente se llama al filename para cada versión del archivo, por lo que terminamos con nombres de archivos como 1312335603175322.jpg y thumb_1312335603195323.jpg. ¿Nota la ligera diferencia? Cada nombre de archivo se basa en el momento en que se llamó el filename para esa versión en particular. Eso no va a hacer en absoluto.

model.created_at me cansé de usar model.created_at para la base de la marca de tiempo. Solo un problema, que devuelve cero para la primera versión, ya que aún no se ha colocado en la base de datos.

Después de pensar un poco más, decidí probar lo siguiente en el controlador de imágenes.

def create if params[:picture] and params[:picture][:image] params[:picture][:image].original_filename = "#{(Time.now.to_i.to_s + Time.now.usec.to_s).ljust(16, ''0'')}#{File.extname(params[:picture][:image].original_filename)}" end ...

Esto anula la propiedad original_filename antes de que Carrierwave llegue a ser una marca de tiempo. Hace exactamente lo que quiero. La versión original del archivo termina con un nombre como 1312332906940106.jpg y la versión en miniatura (o cualquier otra versión) termina con un nombre como thumb_1312332906940106.jpg.

Pero, esto parece un truco horrible. Esto debería ser parte del modelo, o mejor aún, parte del cargador montado en el modelo.

Entonces, mi pregunta es, ¿hay una mejor manera de lograr esto? ¿Me perdí algo crucial con Carrierwave que hace que esto sea fácil? ¿Hay una forma no tan obvia pero más limpia de hacer esto? El código de trabajo es bueno, pero el código de trabajo que no huele mal es mejor.


Verifique también la solución de la wiki de carrierwave disponible ahora https://github.com/carrierwaveuploader/carrierwave/wiki/How-to:-Use-a-timestamp-in-file-names

Puede incluir una marca de tiempo en los nombres de archivo que anulan el nombre de archivo, como puede leer en los documentos de Carrierwave:

class PhotoUploader < CarrierWave::Uploader::Base def filename @name ||= "#{timestamp}-#{super}" if original_filename.present? and super.present? end def timestamp var = :"@#{mounted_as}_timestamp" model.instance_variable_get(var) or model.instance_variable_set(var, Time.now.to_i) end end

No olvide memorizar el resultado en una variable de instancia o puede obtener diferentes marcas de tiempo escritas en la base de datos y en el almacén de archivos.