Bizarrerie d'upload (Webrick)

J’upload un fichier CSV d’adresses e-mail

Un CSV provenant de gmail acceppte de s’uploader (mais contient un
encoding
à problème)

Tous les autres CSV (format outlook, yahoo) provoquent une exception !

Renommage des fichiers, grattage de cuir chevelu, tentative avec
breakpointer qui refuse tout service sous XP, bon !

La ligne en cause :
@imported_file = params[:import_csv_file].path

de cause en désepoir j’essaye :

render :inline => params[:import_csv_file].class.to_s # (je suis dans

un
controller)

Oh surprise !

CSV gmail => Tempfile

CSV autre => StringIO

Donc, au bon vouloir du serveur (ou da Rails ?) on reçoit des objet de
types
distincts ?!

Je recode :

uploaded = params[:import_csv_file]
if uploaded.is_a? StringIO
  render :inline => uploaded.read
elsif uploaded.is_a? Tempfile
  render :inline => uploaded.path
end

et le StringIO contiuent bel et bien le contenu du CSV importé.

OK, j’ai ma solution mais c’est fort de roquefort !

Quelqu’un est déjà tombé là dessus, sous Webrick ou un autre serveur
(Mongrel ?)

Voici le code qui fonctionne chez moi. “import” est la méthode appelée
dans mon controller qui elle-même fait appel aux méthodes “convert” et
“analyze”. En bonus, t’as la gestion de l’encoding (merci à Éric
Jacoboni de m’avoir conseiller charguess) et la gestion des champs du
fichier CSV.

def import
if params[:data].size.zero?
flash[:warn] = ‘Vous avez oublié de choisir un fichier.’
render :action => ‘new’
return
else
params[:data].rewind # Make sure Tempfile / StringIO is at start
of data
data = convert params[:data].string
analyze data
redirect_to :controller => “XXXXXXXX”, :action => “list”
end
end

#charset conversion
def convert txt
input_encoding = CharGuess::guess txt
input_encoding != “UTF-8” ? Iconv.new(“UTF-8”,
input_encoding).iconv(txt) : txt
end

#data analysis
def analyze data
csv_reader = CSV::Reader.create(data)
first_line = csv_reader.shift
lastname_column = first_line.index(“Nom”)
firstname_column = first_line.index(“Prénom”)
email_column = first_line.index(“Adresse de messagerie”)

csv_reader.each{ |row|
  lastname = row[lastname_column]
  firstname = row[firstname_column]
  email = row[email_column]
  #ici on fait le traitement des données
}

end

Le lundi 13 novembre 2006 à 21:57 +0100, philippe lachaise a écrit :

J’upload un fichier CSV d’adresses e-mail

Un CSV provenant de gmail acceppte de s’uploader (mais contient un
encoding à problème)

Tous les autres CSV (format outlook, yahoo) provoquent une exception !

Renommage des fichiers, grattage de cuir chevelu, tentative avec
breakpointer qui refuse tout service sous XP, bon !

Mauvaise plateforme de dev, changer plateforme.

CSV autre => StringIO

Donc, au bon vouloir du serveur (ou da Rails ?) on reçoit des objet de
types distincts ?!

Le type dépend de la taille du fichier uploadé, mais en Ruby, on peut se
permettre de ne pas connaitre la class de l’object (cf prochain
paragraphe).

Je recode :

uploaded = params[:import_csv_file]
if uploaded.is_a? StringIO
  render :inline => uploaded.read
elsif uploaded.is_a? Tempfile
  render :inline => uploaded.path 
end

Ce qui viole le duck typing et est un peu dommage.

++

yk

et le StringIO contiuent bel et bien le contenu du CSV importé.

OK, j’ai ma solution mais c’est fort de roquefort !

Quelqu’un est déjà tombé là dessus, sous Webrick ou un autre serveur
(Mongrel ?)

Non mais j’avais lu ça sur un blog :

http://cleanair.highgroove.com/articles/2006/10/03/mini-file-uploads

Merci pour ces réponses

@Sébastien Gruhier

if 10240 < content_length
Les vaches ! Sans prévenir !

@Yann K.
input_encoding = CharGuess::guess txt
input_encoding != “UTF-8” ? Iconv.new(“UTF-8”,
input_encoding).iconv(txt)
: txt

CharGuess et Iconv c’est pas en standard, faut bien les installer
séparément
?

Le lundi 13 novembre 2006 à 22:45 +0100, philippe lachaise a écrit :

CharGuess et Iconv c’est pas en standard, faut bien les installer
séparément ?

Mhmmm. Pour charguess c’est sûr (et c’est un peu merdique à installer,
mais bon, ça marche, et je ne connais pas d’autres alternatives).
Iconv est peut-être déjà dans Rails (dans Tmail apparemment).

Charguess permet de deviner le charset d’un fichier (ou une chaîne de
caractères).
Iconv permet de transformer un fichier (ou une chaîne de caractères)
d’un charset vers un autre.

++

yk

charguess … c’est un peu merdique à installer
C’est ce que je craignais, tu as une recette pour le setup ?
(qui plus est, il faudrait que ça tourne sur XP en plus de Linux - je
passe
de l’un à l’autre)

Iconv est peut-être déjà dans Rails
On va voir ça…

Le choix StringIO/TempFile vient de cgi.rb de ruby (ligne 986)
if 10240 < content_length
require “tempfile”
body = Tempfile.new(“CGI”)
else
begin
require “stringio”
body = StringIO.new
rescue LoadError
require “tempfile”
body = Tempfile.new(“CGI”)
end
end

avec un bo 10240 en dur!

Le 13 nov. 06 à 21:57, philippe lachaise a écrit :

Le lundi 13 novembre 2006 à 23:11 +0100, philippe lachaise a écrit :

charguess … c’est un peu merdique à installer
C’est ce que je craignais, tu as une recette pour le setup ?
(qui plus est, il faudrait que ça tourne sur XP en plus de Linux - je
passe de l’un à l’autre)

Sous Linux, il faut compiler la bibliothèque libcharguess, puis compiler
la bibliothèque Ruby charguess (qui n’est en fait qu’un wrapper autour
de libcharguess). Sous Linux, ça passe facilement. Sous XP, je ne sais
pas comment ça marche.

Sinon, pour faire un truc un peu plus à l’arrache, tu peux te dire que
si le User-Agent est IE, le charset sera sans doute “CP1252”.

Sinon tu peux laisser faire le boulot de conversion à un programme
Python puisque la bibliothèque “chardet” est un peu plus “accessible”
que ce que l’on trouve dans le monde Ruby (amis trolleurs, bonsoir).

++

yk

2006/11/13, philippe lachaise [email protected]:

Merci pour ces réponses

@Sébastien Gruhier

if 10240 < content_length
Les vaches ! Sans prévenir !

En même temps dans la doc de cgi.rb on peut lire :

"Multipart requests

If a request’s method is POST and its content type is
multipart/form-data, then it may contain uploaded files.
These are stored by the QueryExtension module in the
parameters of the request. The parameter name is the name
attribute of the file input field, as usual. However, the value is
not a string, but an IO object, either an IOString for small files,
or a Tempfile for larger ones."

   -- Jean-François.

Bon voilà un bonne raison d’apprender à compiler sous linux :slight_smile:
Merci pour l’info.

dans la doc de cgi.rb on peut lire

Bon d’accord c’est écrit qqpart, mais appliquer le principe de moindre
surprise ça évite d’avoir besoin d’une deuxième vie pour lire la doc
détaillée de chaque API.