ruby-on-rails - rails - remove image carrierwave
Cómo persistir los campos de carga de archivos después de un error de validación de los rieles. (6)
Bien - Pensé en tomar un enfoque diferente a esto; En lugar de almacenar temporalmente el archivo en el servidor, ¿por qué no volver a enviarlo al cliente para volver a enviarlo cuando el usuario solucione los problemas de validación?
Esto aún podría necesitar un poco de refinamiento, pero es el concepto general:
# in the controller - save the file and its attributes to params
def create
# ...
if params[:doc] # a regular file uploaded through the file form element
# when the form re-renders, it will have those additional params available to it
params[:uploaded_file] = params[:doc].read # File contents
params[:uploaded_file_original_filename] = params[:doc].original_filename
params[:uploaded_file_headers] = params[:doc].headers
params[:uploaded_file_content_type] = params[:doc].content_type
elsif params[:uploaded_file] # a file coming through the form-resubmit
# generate an ActionDispatch::Http::UploadedFile
tempfile = Tempfile.new("#{params[:uploaded_file_original_filename]}-#{Time.now}")
tempfile.binmode
tempfile.write CGI.unescape(params[:uploaded_file]) #content of the file / unescaped
tempfile.close
# merge into the params
params.merge!(doc:
ActionDispatch::Http::UploadedFile.new(
:tempfile => tempfile,
:filename => params[:uploaded_file_original_filename],
:head => params[:uploaded_file_headers],
:type => params[:uploaded_file_content_type]
)
)
end
#...
# params (including the UploadedFile) can be used to generate and save the model object
end
# in the form (haml)
- if !params[:uploaded_file].blank?
# file contents in hidden textarea element
= text_area_tag(:uploaded_file, CGI.escape(params[:uploaded_file]), style: ''display: none;'') #escape the file content
= hidden_field_tag :uploaded_file_headers, params[:uploaded_file_headers]
= hidden_field_tag :uploaded_file_content_type, params[:uploaded_file_content_type]
= hidden_field_tag :uploaded_file_original_filename, params[:uploaded_file_original_filename]
Tengo formulario con varias cargas de archivos. El problema es que cuando envío el formulario y se produce un error de validación, se restablece el campo de entrada del archivo.
Básicamente, quería conservar esos archivos dentro del campo de entrada del archivo para el proceso completo.
También he pasado por algunos enlaces
¿Cómo puedo "mantener" la imagen cargada en un error de validación de formulario?
Por favor, hágame saber cuáles son las diversas opciones en tales casos que uno puede seguir.
Carrierwave es una gran herramienta para manejar cargas de archivos y puede manejar esto por usted
https://github.com/jnicklas/carrierwave#making-uploads-work-across-form-redisplays
Creó un repositorio con un ejemplo del uso de Paperclip en rieles y el mantenimiento de sus archivos cuando se produce un error de validación
Tomé un enfoque completamente diferente a las otras soluciones que se ofrecen aquí, ya que no me apetecía cambiar a CarrierWave o usar otra gema para implementar un truco para evitar esto.
Básicamente, defino placeholders para mensajes de error de validación y luego hago una llamada AJAX al controlador relevante. si fallara la validación, simplemente llenaría los marcadores de posición del mensaje de error, esto deja todo en el lado del cliente, incluyendo la entrada del archivo lista para volver a enviar.
A continuación, se muestra un ejemplo de una organización con un modelo de dirección anidada y un modelo de logotipo anidado (que tiene un archivo adjunto); esto se ha reducido para abreviar:
organizaciones / _form.html.erb
<%= form_for @organisation, html: {class: ''form-horizontal'', role: ''form'', multipart: true}, remote: true do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<p class=''name error_explanation''></p>
<%= f.fields_for :operational_address do |fa| %>
<%= fa.label :postcode %>
<%= fa.text_field :postcode %>
<p class=''operational_address postcode error_explanation''></p>
<% end %>
<%= f.fields_for :logo do |fl| %>
<%= fl.file_field :image %>
<p class=''logo image error_explanation''></p>
<% end %>
<% end %>
organisations_controller.rb
def create
if @organisation.save
render :js => "window.location = ''#{organisations_path}''"
else
render :validation_errors
end
end
organizaciones / validation_errors.js.erb
$(''.error_explanation'').html('''');
<% @organisation.errors.messages.each do |attribute, messages| %>
$(''.<%= attribute %>.error_explanation'').html("<%= messages.map{|message| "''#{message}''"}.join('', '') %>");
<% end %>
Tuve que arreglar esto en un proyecto reciente usando Paperclip Gem. Es un poco hacky pero funciona. Intenté llamar a cache_images () usando after_validation y before_save en el modelo pero falla al crear por algún motivo que no puedo determinar, así que simplemente lo llamo desde el controlador. ¡Ojalá esto le ahorre a alguien más algo de tiempo!
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: ''''}
Una solución para esto en lugar de una solución absoluta es usar la validación del lado del cliente para que el archivo no se pierda porque todo el formulario persiste.
Los pocos usuarios que no tienen habilitado JavaScript perderán los archivos entre las solicitudes, pero quizás este% sea tan bajo para que sea un compromiso aceptable. Si esta es la ruta que decides bajar, te recomendaría esta joya
https://github.com/bcardarella/client_side_validations
Lo que hace que todo el proceso sea realmente simple y significa que no tiene que volver a escribir su validación en JavaScript