Depuis que je me suis mis au Ruby on Rails, et donc initié au modèle MVC, j'ai toujours été stupéfait de voir un grand nombre de développeurs "gérer" les fichiers externes, envoyés par les internautes, dans leur controller ou leur model.
La logique même de séparation concepts différents aurait dû, selon moi, les inciter à créer des "medias manager", ou sortes de classes/modules pour gérer ces fichiers externes, de leur naissance à leur destruction.
N'ayant pas trouvé ce que je cherchais, j'ai créé il y a quelques mois un couple FileHandler/ImageHandler que j'ai étendu par la suite pour gérer les sons et vidéos. N'ayant depuis jamais encore trouvé de meilleure solution, j'aimerais bien savoir ce que vous en pensez. Voici donc une courte présentation de tout cela :

Et voici un exemple d'utilisation concret, une fois que les fichiers ont bien été 'required' comme il se doit :
in the view (app/views/photos/new.rhtml) :
<% form_for(:photo, :url => photos_path, :html => {:multipart => true}) do |f| %>
<%= error_messages_for(:photo) %>
<%=mff 'Sélectionnez le fichier à envoyer', file_field_tag(:file) %>
<%=mff 'Description (facultatif)', f.text_area(:description) %>
<p class="submit"><%= submit_tag('Envoyer cette photo »»') %></p>
<% end %>
in the controller (app/controllers/photos_controller.rb) :
class PhotosController < ApplicationController
#[...]
def create
@photo = Photo.create(params[:photo])
@photo.store(params[:file])
if @photo.save
flash[:notice] = "Nouvelle photo enregistrée."
redirect_to :action => 'new'
else
@photo.destroy
render :action => 'new'
end
end
#[...]
end
in the model (app/models/photo.rb) :
class Photo < ActiveRecord::Base
before_destroy { |record| ImageHandler.delete_with_thumbnails(record.file_name) }
def store(iostream)
image = ImageHandler.new(iostream)
begin
image.store(self.id) # son nom de fichier sera son id + extension
rescue
@erreurs = $!.to_s # si une exception remonte l'ImageHandler ou du FileHandler, on l'ajoute à la liste d'erreurs de validations ActiveRecord
else
image.make_thumbnails 100, 150, 200, 250, 300 # chaque nombre représente le width d'un thumbnail de l'image qui sera fait
update_attribute :file_name, image.raw_name # on rentre son nom dans la bdd
end
end
protected
def validate
errors.add_to_base(@erreurs) if defined?(@erreurs) # l'ajout à la base se fait ici en réalité
end
end