registrarse referencia problemas preguntas para numero frecuentes cual con como codigo actualizar ruby-on-rails validation paperclip attachment

ruby-on-rails - problemas - numero de referencia clip



No perder el accesorio del clip cuando no se puede guardar el modelo debido a un error de validaciĆ³n (8)

A partir de septiembre de 2013, el clip no tiene la intención de "arreglar" la pérdida de archivos adjuntos después de la validación. "El problema es (IMHO) más fácil y más correctamente evitado que resuelto"

https://github.com/thoughtbot/paperclip/issues/72#issuecomment-24072728

Estoy considerando la solución CarrierWave propuesta en la solución anterior de John Gibb

El escenario es un modelo normal que contiene un adjunto de clip junto con algunas otras columnas que tienen varias validaciones. Cuando no se puede guardar un formulario para crear un objeto debido a un error de validación no relacionado con el archivo adjunto, las columnas como cadenas se conservan y se rellenan previamente para el usuario, pero el archivo seleccionado para la carga se pierde por completo y el usuario debe volver a seleccionarlo.

¿Existe un enfoque estándar para preservar el archivo adjunto en el caso de un error de validación del modelo? Esto parece un caso de uso muy común.

Parece poco elegante hackear una solución donde el archivo se guarda sin un propietario y luego se vuelve a conectar al objeto después de que se haya guardado con éxito, así que espero evitarlo.


Cambie a utilizar CarrierWave. Sé que esto estaba en un comentario, pero acabo de pasar todo el día haciendo la transición, por lo que mi respuesta puede ser útil todavía.

Primero, puede seguir un gran panorama sobre la configuración de wave wave: http://railscasts.com/episodes/253-carrierwave-file-uploads

Para lograr que se conserve la imagen entre las publicaciones, debe agregar un campo oculto con el sufijo ''caché'':

<%= form_for @user, :html => {:multipart => true} do |f| %> <p> <label>My Avatar</label> <%= f.file_field :avatar %> <%= f.hidden_field :avatar_cache %> </p> <% end %>

Para Heroku

Y si está implementando en Heroku como lo soy yo, necesita hacer algunos cambios para que funcione, ya que el almacenamiento en caché funciona al guardar temporalmente las cargas en un directorio llamado public / uploads. Dado que el sistema de archivos es de solo lectura en Heroku, necesita que use la carpeta tmp en su lugar, y que el rack sirva archivos estáticos desde allí.

Dile a carrierwave que use la carpeta tmp para el almacenamiento en caché.

En su config / initializers / carrierwave.rb (siéntase libre de crear si no está allí), agregue:

CarrierWave.configure do |config| config.root = Rails.root.join(''tmp'') config.cache_dir = ''carrierwave'' end

Configure el bastidor para servir archivos estáticos desde la carpeta tmp / carrierwave

En su archivo config.ru, agregue:

use Rack::Static, :urls => [''/carrierwave''], :root => ''tmp''

Para ver un ejemplo de una aplicación barebones rails / carrierwave / s3 / heroku completamente funcional, echa un vistazo a:

https://github.com/trevorturk/carrierwave-heroku (sin afiliación, solo fue útil).

¡Espero que esto ayude!


En el archivo de vista, simplemente ponga si la condición debe aceptar solo el registro que tenía una identificación válida. En mi escenario este es el fragmento de código

<p>Uploaded files:</p> <ul> <% @user.org.crew.w9_files.each do |file| %> <% if file.id.present? %> <li> <%= rails code to display value %> </li> <% end %> <% end %> </ul>


Guarda tu foto primero que prueba el resto

Digamos que tienes un usuario con un avatar de clip:

def update @user = current_user unless params[:user][:avatar].nil? @user.update_attributes(avatar: params[:user][:avatar]) params[:user].delete :avatar end if @user.update_attributes(params[:user]) redirect_to edit_profile_path, notice: ''User was successfully updated.'' else render action: "edit" end end


Si no se requiere la imagen, ¿por qué no dividir el formulario en dos etapas, la primera crea el objeto, la segunda página le permite agregar información opcional (como una foto)?

Alternativamente, puede validar el formulario a medida que el usuario ingresa la información para que no tenga que enviar el formulario para descubrir que sus datos no son válidos.


Siguiendo la idea de @galatians, obtuve esta solución (y trabajé muy bien)

Creé un repositorio para ese ejemplo: * https://github.com/mariohmol/paperclip-keeponvalidation

  1. Lo primero que debe hacer es poner algunos métodos en su registro activo base, para que cada modelo que use el adjunto pueda hacer que funcione

En config / initializers / active_record.rb

module ActiveRecord class Base def decrypt(data) return '''' unless data.present? cipher = build_cipher(:decrypt, ''mypassword'') cipher.update(Base64.urlsafe_decode64(data).unpack(''m'')[0]) + cipher.final end def encrypt(data) return '''' unless data.present? cipher = build_cipher(:encrypt, ''mypassword'') Base64.urlsafe_encode64([cipher.update(data) + cipher.final].pack(''m'')) end def build_cipher(type, password) cipher = OpenSSL::Cipher::Cipher.new(''DES-EDE3-CBC'').send(type) cipher.pkcs5_keyivgen(password) cipher end #ex: @avatar_cache = cache_files(avatar,@avatar_cache) def cache_files(avatar,avatar_cache) if avatar.queued_for_write[:original] FileUtils.cp(avatar.queued_for_write[:original].path, avatar.path(:original)) avatar_cache = encrypt(avatar.path(:original)) elsif avatar_cache.present? File.open(decrypt(avatar_cache)) {|f| assign_attributes(avatar: f)} end return avatar_cache end end end

  1. Después de eso, incluya en su modelo y campo adjunto, el código anterior

En el ejemplo, lo incluí en /models/users.rb

has_attached_file :avatar, PaperclipUtils.config attr_accessor :avatar_cache def cache_images @avatar_cache=cache_files(avatar,@avatar_cache) end

  1. En su controlador, agregue esto para obtener de la memoria caché la imagen (justo antes del punto donde guarda el modelo)

    @ user.avatar_cache = params [: usuario] [: avatar_cache]

    @ user.cache_images

    @ user.save

  2. Y finalmente incluya esto en su vista, para registrar la ubicación de la imagen temporal actual

f.hidden_field: avatar_cache

  1. Si desea mostrar en la vista el archivo real, inclúyalo:

<% if @user.avatar.exists? %> <label class="field">Actual Image </label> <div class="field file-field"> <%= image_tag @user.avatar.url %> </div> <% end %>


También refile ver refile (opción más reciente)

Caracteristicas :

  • Backends configurables, sistema de archivos, S3, etc ...
  • Conveniente integración con ORMs
  • Manipulación de imágenes y otros archivos sobre la marcha.
  • Streaming de IO para cargas rápidas y con memoria
  • Funciona en redisplay de formularios, es decir, cuando fallan las validaciones, incluso en S3
  • Cargas directas sin esfuerzo, incluso a S3
  • Soporte para múltiples cargas de archivos

https://gorails.com/episodes/file-uploads-with-refile


Tuve que arreglar esto en un proyecto reciente usando PaperClip. He intentado llamar cache_images () usando after_validation y before_save en el modelo, pero falla en la creación por alguna razón que no puedo determinar, así que solo lo llamo desde el controlador.

modelo:

class Shop < ActiveRecord::Base attr_accessor :logo_cache has_attached_file :logo def cache_images if logo.staged? if invalid? FileUtils.cp(logo.queued_for_write[:original].path, logo.path(:original)) @logo_cache = encrypt(logo.path(:original)) end else if @logo_cache.present? File.open(decrypt(@logo_cache)) {|f| assign_attributes(logo: f)} end end end private def decrypt(data) return '''' unless data.present? cipher = build_cipher(:decrypt, ''mypassword'') cipher.update(Base64.urlsafe_decode64(data).unpack(''m'')[0]) + cipher.final end def encrypt(data) return '''' unless data.present? cipher = build_cipher(:encrypt, ''mypassword'') Base64.urlsafe_encode64([cipher.update(data) + cipher.final].pack(''m'')) end def build_cipher(type, password) cipher = OpenSSL::Cipher::Cipher.new(''DES-EDE3-CBC'').send(type) cipher.pkcs5_keyivgen(password) cipher end end

controlador:

def create @shop = Shop.new(shop_params) @shop.user = current_user @shop.cache_images if @shop.save redirect_to account_path, notice: ''Shop created!'' else render :new end end def update @shop = current_user.shop @shop.assign_attributes(shop_params) @shop.cache_images if @shop.save redirect_to account_path, notice: ''Shop updated.'' else render :edit end end

ver:

= f.file_field :logo = f.hidden_field :logo_cache - if @shop.logo.file? %img{src: @shop.logo.url, alt: ''''}