Subiendo con rieles y Paperclip

Este es el último artículo de la serie "Cargar con rieles". En los últimos meses, ya hemos hablado de las gemas Shrine, Dragonfly y Carrierwave. El invitado de hoy es Paperclip by Thoughtbot, una compañía que maneja gemas como FactoryGirl y Bourbon.

Paperclip es probablemente la solución de gestión de archivos adjuntos más popular para Rails (más de 13 millones de descargas), y por una buena razón: tiene muchas características, una gran comunidad y documentación exhaustiva. Así que espero que estés ansioso por aprender más sobre esta joya!

En este artículo aprenderás cómo:

  • Preparar para la instalación de Paperclip
  • Integrar Paperclip en una aplicación de Rails
  • Añadir validaciones de adjuntos
  • Generar miniaturas y procesar imágenes.
  • Ofuscar URL
  • Almacenar archivos adjuntos en Amazon S3
  • Asegure los archivos en la nube mediante la introducción de la lógica de autorización

El código fuente de este artículo está disponible en GitHub..

Preparativos

Antes de adentrarnos en el código, analicemos en primer lugar algunas advertencias que debe conocer para poder trabajar con éxito con Paperclip:

  • La última versión de Paperclip es compatible con Rails 4.2+ y Ruby 2.1+. Esta gema también se puede utilizar sin rieles..
  • ImageMagick debe estar instalado en su PC (está disponible para todas las plataformas principales), y Paperclip debe poder acceder a él.
  • los expediente El comando debe estar disponible desde la línea de comandos. Para Windows, está disponible a través del kit de desarrollo, así que siga estas instrucciones si aún no tiene DevKit instalado.

Cuando esté listo, continúe y cree una nueva aplicación de Rails (usaré Rails 5.0.2) sin el paquete de prueba predeterminado:

rieles nuevos UcomingWithPaperclip -T

Paperclip Integrante

Caer en la gema Paperclip:

Gemfile

gema "clip", "~> 5.1"

Instalarlo:

instalación de paquete

Supongamos que estamos creando una aplicación de estantería que presenta una lista de libros. Cada libro tendrá un título, una descripción, el nombre de un autor y una imagen de portada. Para empezar, genere y aplique la siguiente migración:

rieles modelo g Título del libro: cadena descripción: imagen de texto: adjunto autor: cadena rieles db: migrar

Nota la adjunto archivo Tipo que nos presenta Paperclip. Bajo el capó, va a crear cuatro campos para nosotros:

  • nombre_archivo_imagen
  • image_file_size
  • image_content_type
  • image_updated_at

A diferencia de las gemas Shrine y Carrierwave, Paperclip no tiene un archivo separado con configuraciones. Todas las configuraciones se definen dentro del propio modelo usando la has_attached_file Método, así que agrégalo ahora:

modelos / libro.rb

has_attached_file: imagen

Antes de continuar con la parte principal, también creamos un controlador junto con algunas vistas y rutas.

Creando el Controlador, Vistas y Rutas

Nuestro controlador será muy básico:

libros_controller.rb

clase BooksController < ApplicationController before_action :set_book, only: [:show, :download] def index @books = Book.order('created_at DESC') end def new @book = Book.new end def show end def create @book = Book.new(book_params) if @book.save redirect_to books_path else render :new end end private def book_params params.require(:book).permit(:title, :description, :image, :author) end def set_book @book = Book.find(params[:id]) end end

Aquí hay una índice vista y una parcial:

vistas / libros / index.html.erb

Estante para libros

<%= link_to 'Add book', new_book_path %>
    <%= render @books %>

views / books / _book.html.erb

  • <%= link_to book.title, book_path(book) %> por <%= book.author %>
  • Ahora las rutas:

    config / route.rb

    Rails.application.routes.draw do resources: raíz de libros a final de 'books # index' 

    ¡Bonito! Ahora vamos a la sección principal y codificamos el nuevo acción y una forma.

    Cargando archivos

    Con todo, hacer subidas con Paperclip es fácil. Solo necesita permitir el atributo correspondiente (en nuestro caso ese es el imagen atributo, y ya lo hemos permitido) y presentamos un campo de archivo en su formulario. Hagámoslo ahora:

    views / books / new.html.erb

    Añadir libro

    <%= render 'form', book: @book %>

    views / books / _form.html.erb

    <%= form_for book do |f| %> 
    <%= f.label :title %> <%= f.text_field :title %>
    <%= f.label :author %> <%= f.text_field :author %>
    <%= f.label :description %> <%= f.text_area :description %>
    <%= f.label :image %> <%= f.file_field :image %>
    <%= f.submit %> <% end %>

    Con esta configuración, ya puede comenzar a realizar subidas, pero también es una buena idea introducir algunas validaciones..

    Agregando Validaciones

    Las validaciones en Paperclip se pueden escribir usando antiguos ayudantes como validates_attachment_presencevalidates_attachment_content_type o empleando el validates_attachment Método para definir múltiples reglas a la vez. Sigamos con la última opción:

    modelos / libro.rb

     validates_attachment: image, content_type: content_type: /\Aimage\/.*\z/, tamaño: less_than: 1.megabyte

    El código es realmente simple, como puedes ver. Requerimos que el archivo sea una imagen de menos de 1 megabyte de tamaño. Tenga en cuenta que si la validación falla, no se realizará ningún procesamiento posterior. Paperclip ya tiene algunos mensajes de error establecidos para el idioma inglés, pero si desea admitir otros idiomas, incluya la gema paperclip-i18n en su Gemfile.

    Otra cosa importante a mencionar es que Paperclip requiere que valide el tipo de contenido o el nombre de archivo de todos los archivos adjuntos, de lo contrario generará un error. Si está 100% seguro de que no necesita tales validaciones (lo cual es un caso raro), use do_not_validate_attachment_file_type para decir explícitamente qué campos no deben ser marcados.

    Habiendo agregado validaciones, también mostremos mensajes de error en nuestro formulario:

    views / shared / _errors.html.erb

    <% if object.errors.any? %> 

    Se encontraron algunos errores:

      <% object.errors.full_messages.each do |message| %>
    • <%= message %>
    • <% end %>
    <% end %>

    views / books / _form.html.erb

    <%= render 'shared/errors', object: book %>

    Visualización de imágenes

    Bien, ahora las imágenes subidas deberían mostrarse de alguna manera. Esto se hace usando el etiqueta_imagen ayudante y un url método. Crear un espectáculo ver:

    views / books / show.html.erb

    <%= @book.title %> por <%= @book.author %>

    <%= image_tag(@book.image.url) if @book.image.exists? %>

    <%= @book.description %>

    Solo estamos mostrando una imagen si realmente existe en el disco. Además, si está utilizando almacenamiento en la nube, Paperclip realizará una solicitud de red y comprobará la existencia del archivo. Por supuesto, esta operación puede llevar algún tiempo, por lo que puede usar el presente? o expediente? métodos en su lugar: simplemente se asegurarán de que nombre_archivo_imagen campo se rellena con algún contenido.

    Ofuscación URI

    Por defecto, todos los archivos adjuntos se almacenan dentro de la público / sistema carpeta, por lo que probablemente querrá excluirla del sistema de control de versiones: 

    .gitignore

    público / sistema

    Sin embargo, mostrar un URI completo en el archivo no siempre es una buena idea, y es posible que deba ofuscarlo de alguna manera. La forma más fácil de habilitar la ofuscación es proporcionar dos parámetros a la método has_attached_file:

    modelos / libro.rb

    url: "/system/:hash.:extension", hash_secret: "longSecretString"

    Los valores adecuados serán interpolados en el url automáticamente. hash_secret es un campo obligatorio y la forma más fácil de generarlo es mediante:

    secreto de carriles

    Trabajando con estilos

    En muchos casos, es preferible mostrar la miniatura de una imagen con un ancho y alto predefinidos para ahorrar ancho de banda. Paperclip resuelve esto usando estilos: cada estilo tiene un nombre y un conjunto de reglas, como dimensiones, formato, calidad, etc..

    Supongamos que queremos que la imagen original y su miniatura se conviertan al formato JPEG. La miniatura debe recortarse a 300 x 300 px:

    modelos / libro.rb

     has_attached_file: imagen, estilos: pulgar: ["300x300 #",: jpeg], original: [: jpeg]

    # es un significado de configuración de geometría: "Recortar si es necesario mientras se mantiene la relación de aspecto".

    También podemos proporcionar opciones de conversión adicionales para cada estilo. Por ejemplo, proporcionemos un 70% de calidad para los pulgares mientras eliminamos todos los metadatos y un 90% de calidad para la imagen original para hacerla un poco más pequeña:

    modelos / libro.rb

     has_attached_file: imagen, estilos: thumb: ["300x300 #",: jpeg], original: [: jpeg], convert_options: thumb: "-quality 70 -strip", original: "-quality 90"

    ¡Bonito! Muestre la miniatura y proporcione el enlace a la imagen original:

    views / books / show.html.erb

    <%= link_to(image_tag(@book.image.url(:thumb)), @book.image.url, target: '_blank') if @book.image.exists? %> 

    Tenga en cuenta que, a diferencia de Carrierwave, por ejemplo, Paperclip no le permite escribir @ book.image.thumb.url.

    Si, por alguna razón, desea actualizar manualmente las imágenes cargadas, entonces puede usar los siguientes comandos para actualizar solo las miniaturas, agregar estilos faltantes o actualizar todas las imágenes:

    • clip de rastrillo: actualizar: miniaturas CLASE = Libro
    • clip de rastrillo: actualizar: missing_styles CLASE = Libro
    • clip de rastrillo: actualizar CLASE = Libro

    Almacenamiento de archivos en la nube

    Como todas las soluciones similares, Paperclip le permite cargar archivos a la nube. Fuera de la caja, es compatible con los adaptadores S3 y Fog, pero también hay gemas de terceros para Azure y Dropbox. En esta sección, le mostraré cómo integrar Paperclip con Amazon S3. Primero, suelta la gema aws-sdk:

    gema 'aws-sdk'

    Instalarlo:

    instalación de paquete

    A continuación, proporcione un nuevo conjunto de opciones a la has_attached_file método:

    modelos / libro.rb

     has_attached_file: imagen, estilos: thumb: ["300x300 #",: jpeg], original: [: jpeg], convert_options: thumb: "-quality 70 -strip", original: "-quality 90", almacenamiento :: s3, s3_credentials: access_key_id: ENV ["S3_KEY"], secret_access_key: ENV ["S3_SECRET"], bucket: ENV ["S3_BUCKET"], s3_region: ENV ["S3_REGION"]

    Aquí me atengo a la gema dotenv-rails para establecer variables de entorno. Puede proporcionar todos los valores directamente dentro del modelo, pero no lo haga público.

    Lo interesante es que s3_credenciales también acepta una ruta de acceso a un archivo YAML que contiene sus claves y un nombre de depósito. Además, puede establecer diferentes valores para diferentes entornos como este: 

    desarrollo: access_key_id: key1 secret_access_key: secret1 producción: access_key_id: key2 secret_access_key: secret2

    ¡Eso es! Todos los archivos que subas ahora estarán ubicados en tu cubo S3.

    Proteger archivos en la nube

    Supongamos que no desea que sus archivos cargados estén disponibles para todos. De forma predeterminada, todas las cargas en la nube están marcadas como públicas, lo que significa que cualquier persona puede abrir el archivo a través del enlace directo. Si desea introducir alguna lógica de autorización y verificar quién puede ver el archivo, configure la s3_permisiones opción a :privado Me gusta esto:

     has_attached_file: imagen, estilos: thumb: ["300x300 #",: jpeg], original: [: jpeg], convert_options: thumb: "-quality 70 -strip", original: "-quality 90", almacenamiento :: s3, s3_credentials: access_key_id: ENV ["S3_KEY"], secret_access_key: ENV ["S3_SECRET"], bucket: ENV ["S3_BUCKET"], s3_region: ENV ["S3_REGION"], s3px

    Ahora, sin embargo, nadie excepto tú podrá ver los archivos. Por lo tanto, vamos a crear una nueva descargar acción para el Controles de libros:

    libros_controller.rb

     def descarga redirect_to @ book.image.expiring_url end

    Esta acción simplemente redirigirá a los usuarios a la imagen a través de un enlace que caduca. Usando este enfoque, ahora puede introducir cualquier lógica de autorización usando gemas como CanCanCan o Pundit.

    No te olvides de establecer la ruta de miembros:

    config / route.rb

     recursos: los libros no obtienen los miembros final de descarga

    El ayudante debe ser usado así:

    link_to ('Ver imagen', download_book_path (@book), destino: '_blank')

    Conclusión

    ¡Hemos llegado al final de este artículo! Hoy hemos visto a Paperclip, una solución de gestión de archivos adjuntos para Rails, en acción y hemos discutido sus conceptos principales. Hay mucho más en esta joya, así que asegúrese de ver su documentación..

    Además, recomiendo visitar la página wiki de Paperclip, ya que presenta una lista de "tutoriales" y un montón de enlaces a gemas de terceros que admiten Azure y Cloudinary y que le permiten minimizar fácilmente los archivos cargados.

    Gracias por estar conmigo y hasta pronto.!