Questo può essere un po 'tardi per il PO, ma spero che questo aiuta qualcuno. Avevo bisogno di memorizzare un'immagine caricata nella sessione dell'utente (di nuovo per un modulo in più fasi), e anch'io ho iniziato con Ryan Railscast #217, ma l'applicazione si è rapidamente evoluta oltre. Si noti che il mio ambiente era Rails 4 su Ruby 2, utilizzando Carrierwave e MiniMagick, nonché activerecord-session_store, che spiegherò di seguito.
Credo che il problema che entrambi io e OP avevamo era che stavamo cercando di aggiungere tutti i parametri POST alla sessione dell'utente, ma con un caricamento di file, uno dei parametri era un oggetto UploadedFile, che è molto alla grande per quello. L'approccio descritto di seguito è un'altra soluzione a questo problema.
Disclaimer: Come è ampiamente noto, non è l'ideale per memorizzare oggetti complessi in sessione di un utente, meglio conservare gli identificatori di registrazione o altri dati identificativi (ad esempio il percorso di un'immagine) e cercare i dati quando necessario. Due motivi principali per questo mantenendo sincronizzati i dati di sessione e modello/database (un'attività non banale) e l'archivio di sessione di Rails predefinito (utilizzando i cookie) è limitato a 4kb.
mio modello (submission.rb):
class Submission < ActiveRecord::Base
mount_uploader :image_original, ImageUploader
# ...
end
Controller (submissions_controller.rb):
def create
# If the submission POST contains an image, set it as an instance variable,
# because we're going to remove it from the params
if params[:submission] && params[:submission][:image_original] && !params[:submission][:image_original].is_a?(String)
# Store the UploadedFile object as an instance variable
@image = params[:submission][:image_original]
# Remove the uploaded object from the submission POST params, since we
# don't want to merge the whole object into the user's session
params[:submission].delete(:image_original)
end
# Merge existing session with POST params
session[:submission_params].deep_merge!(params[:submission]) if params[:submission]
# Instantiate model from newly merged session/params
@submission = Submission.new(session[:submission_params])
# Increment the current step in the session form
@submission.current_step = session[:submission_step]
# ... other steps in the form
# After deep_merge, bring back the image
if @image
# This adds the image back to the Carrierwave mounted uploader (which
# re-runs any processing/versions specified in the uploader class):
@submission.image_original = @image
# The mounted uploader now has the image stored in the Carrierwave cache,
# and provides us with the cache identifier, which is what we will save
# in our session:
session[:submission_params][:image_original] = @submission.image_original_cache
session[:image_processed_cached] = @submission.image_original.url(:image_processed)
end
# ... other steps in the form
# If we're on the last step of the form, fetch the image and save the model
if @submission.last_step?
# Re-populate the Carrierwave uploader's cache with the cache identifier
# saved in the session
@submission.image_original_cache = session[:submission_params][:image_original]
# Save the model
@submission.save
# ... render/redirect_to ...
end
end
Il mio file uploader è stato soprattutto scorta con qualche trattamento personalizzato.
Nota: per potenziare le sessioni, sto utilizzando activerecord-session_store, che è una gemma che è stata estratta dal nucleo di Rails nella v4 che fornisce un archivio di sessione supportato da database (aumentando così il limite della sessione di 4kb). Seguire the documentation per le istruzioni di installazione, ma nel mio caso è stato abbastanza veloce e indolore impostare e dimenticarlo. Nota per gli utenti con traffico elevato: i record della sessione rimanenti non sembrano essere eliminati dalla gemma, quindi se si riceve abbastanza traffico questa tabella potrebbe potenzialmente passare a un numero indicibile di righe.
stai caricando un file immagine o un file di parole Microsoft? –
ho bisogno di convalidare il tipo di file prima di caricarlo – AlphaB
Si dovrebbe prendere il 'CarrierWave :: IntegrityError' o usare il metodo' store() '(senza!), Così come non lancia l'errore. –