2010-02-09 24 views
18

Sai, su alcuni siti quando ti viene chiesto di caricare, ad esempio, un avatar, fai clic sul pulsante, seleziona il file, quindi premi OK, ma prima dello tu Invia la pagina (come in, nessun record è stato creato/aggiornato), viene visualizzata una piccola anteprima dell'immagine?Rails: graffetta e anteprime?

Come posso ottenere questo utilizzando Paperclip per Rails?

Punti bonus per chiunque possa indicarmi un tutorial o qualcosa che potrebbe dirmi come fare un ritaglio Javascript sull'immagine prima di salvare il record.

Non sono stato in grado di trovare molto su Google in materia ... grazie per l'aiuto!

risposta

19

Questo tipo di problema è problematico dal punto di vista di Rails a causa del modo in cui funzionano i caricamenti di immagini. Una strategia per farlo funzionare meglio è:

  • Fai un sotto-modulo per il caricamento delle immagini, possibilmente utilizzando swfupload per renderlo più snello.
  • Creare un modello per ricevere i tuoi caricamenti che include una chiave di accesso casuale utilizzata per recuperarla e collegarla. Paperclip gestisce il file allegato.
  • Utilizzare AJAX per compilare il modulo principale inserendo un campo nascosto o potenzialmente un elemento di casella di controllo visibile con il tasto unique appropriato, al termine della sottomaschera.

Un modello tipico simile a questa:

class Avatar < ActiveRecord::Base 
    has_attached_file :image 
    # ... Additional Paperclip options here 

    before_validation :assign_unique_key 

    belongs_to :user 

    def to_param 
    self.unique_key 
    end 

protected 
    def assign_unique_key 
    return if (self.unique_key.present?) 

    self.unique_key = Digest::SHA1.hexdigest(ActiveSupport::SecureRandom.random_number(1<<512).to_s) 
    end 
end 

Il motivo per il campo unique_key è così che si può collegare questo per la forma di un disco potenzialmente non salvati. È vantaggioso utilizzare il tasto unique_key anziché id quando lo si inserisce negli URL, poiché è difficile stabilire se un utente debba essere in grado di vedere o meno questa immagine quando viene caricata poiché l'utente proprietario non può ancora essere assegnato.

Ciò impedisce anche alle persone curiose di alterare un tipo di ID sequenziale e facilmente ipotizzabile nel proprio URL e di vedere altri avatar che sono stati caricati.

È possibile recuperare l'ultimo URL ridimensionato dell'anteprima per l'Avatar come si farebbe con qualsiasi modello a questo punto.

Si può facilmente striscia fuori i parametri al ricevimento e tradurre di nuovo a numeri ID Avatar:

# If an avatar_id parameter has been assigned... 
if (params[:user][:avatar_id]) 
    # ...resolve this as if it were a unique_key value... 
    avatar = Avatar.find_by_unique_key(params[:user][:avatar_id]) 
    # ...and repopulate the parameters if it has been found. 
    params[:user][:avatar_id] = (avatar && avatar.id) 
end 

# ... params[:user] used as required for create or update 

Come persone caricare e ricaricare le immagini, vi troverete infine avere un gran numero di record orfani che non sono effettivamente usato ovunque È semplice scrivere un'attività di rake per eliminare tutto ciò dopo che è trascorso un ragionevole lasso di tempo. Ad esempio:

task :purge_orphan_avatars => :environment do 
    # Clear out any Avatar records that have not been assigned to a particular 
    # user within the span of two days. 
    Avatar.destroy_all([ 'created_at<? AND user_id IS NULL', 2.days.ago ]) 
end 

Uso destroy_all dovrebbero avere l'effetto di spurgo tutto il materiale graffetta pure.

5

ho trovato la soluzione postato here utile, è solo bisogno di modificarlo in modo da essere un solo file (se si sta facendo singolo file):

<%= image_tag @upload.image, id:"something_unique"%> 
<div class="row"> 
    <%= form_for @upload, :html => { :multipart => true } do |f| %> 
    <%= f.file_field :image, id:"something_else_unique" %> 
    <%= f.submit "Add photo" %> 
    <% end %> 
</div> 

<script> 
    function handleFileSelect(evt) { 
    var files = evt.target.files; // FileList object 
     f=files[0] 
     // Only process image files. 
     if (f.type.match('image.*')) { 
     var reader = new FileReader(); 
     reader.onload = (function(theFile) { 
      return function(e) { 
      // alert(e.target.result); 
      document.getElementById("something_unique").src=e.target.result; 
      }; 
     })(f); 

     // Read in the image file as a data URL. 
     reader.readAsDataURL(f); 
     } 
    } 
    document.getElementById('something_else_unique').addEventListener('change', handleFileSelect, false); 
</script> 

Nota: ho utilizzato un modello separato per paperclip, un modello di caricamento con l'attributo dell'immagine. È possibile aggiungere uno stile al tag di anteprima dell'immagine per formattare la dimensione dell'immagine (altrimenti sarà la dimensione originale).

Problemi correlati