Vues, typecasting et représentation

Bonjour,

J’ai un problème assez récurrent en rails dont je n’arrive pas à trouver
une solution optimale.

En fait, ma problématique est d’afficher des données dans un format
“maison”.

Exemple:

En base, je vais avoir un float qui correspond à des heures.

1.5 => 1:30

J’ai fait un helper qui à cette tête là :

class ActionView::Helpers::FormBuilder

def hours_text_field(method, options={})
if options[:value].is_a?(Float)
options[:value] = options[:value].to_h
end
text_field method, options
end

end

le to_h me convertit le float en heures.

Dans ma vue, j’ai donc ceci :

<%= f.hours_text_field :mon_champ, :value => @monmodele.monchamp %>

Et j’ai divers problèmes:

Le premier d’entre eux se situe dans le retour sur erreur: en effet, la
valeur va être à nouveau convertit en “heures” alors que je voudrais
laisser la valeur initialement entrée.

Deuxieme probleme, au moment de la mise en base, le modele typecast le
champ en float sans que je puisse rien y faire. Je ne peux pas dériver
le string_to_float de ActiveRecord::ConnectionAdapters::Column vu que
dans mon application, j’ai deux interprétations pour le même type de
champ en base.

En général, le problème d’interprétation des champs dans une vue me pose
problème dès que je sors de la représentation “classique” de ce type de
champ.

Des idées ?

Des floats pour stocker des heures… beurk.

Mais bon, si tu y tiens, un petit truc que tu peux mettre dans ton
modèle :

def mon_champs_in_hours
… # mon_champs => float => string
end

def mon_champs_in_hours= value
… # string => float => mon_champs
end

Et du coup, dans ta vue :

<%= f.text_field :mon_champs_in_hours %>

Ceci dit, pourquoi ne pas stocker cette valeur tout simplement en texte
?

Michel B.

2009/7/7 Guillaume M. [email protected]

Michel B. wrote:

Des floats pour stocker des heures… beurk.

Ceci dit, pourquoi ne pas stocker cette valeur tout simplement en texte
?

Michel B.

2009/7/7 Guillaume M. [email protected]

J’ai justement un probleme de double représentation d’où la
représentation en float car je stock un span en vérité et non un stamp
en heures. De plus, les utilisateurs veulent pouvoir rentrer soit 1:30
soit 1.5 d’où le stockage en float.

J’aurais pu te mettre l’exemple des dates à afficher et à valider sous
la forme “DD/MM/YYYY” dans un edit mais là pour le coup, j’avais trouvé
la solution en faisant un helper, une validation pour les dates et en
surchargeant string_to_date.

Je connaissais la méthode que tu as précisé mais je me demandais si l’on
ne pouvait pas attaquer rails à plus bas niveau.

Merci :wink:

J’ai justement un probleme de double représentation d’où la
représentation en float car je stock un span en vérité et non un stamp
en heures.

En la stockant sous forme de chaîne tu peux la stocker sous la forme 1.5
sans problème, et même faire des calculs avec.

De plus, les utilisateurs veulent pouvoir rentrer soit 1:30
soit 1.5 d’où le stockage en float.

De toute façon 1:30 de force à faire une conversion de chaîne vers
float. Ca
ne changerait pas grand chose du point de vue fonctionnel de stocker en
chaîne.

J’aurais pu te mettre l’exemple des dates à afficher et à valider sous

la forme “DD/MM/YYYY” dans un edit mais là pour le coup, j’avais trouvé
la solution en faisant un helper, une validation pour les dates et en
surchargeant string_to_date.

Je connaissais la méthode que tu as précisé mais je me demandais si l’on
ne pouvait pas attaquer rails à plus bas niveau.

Pourquoi faire du “bas niveau”, là de toute façon ton problème se trouve
Ã
mi-chemin entre la présentation et le métier, donc un petit coup de
métier
pour s’assurer que la conversion est factorisée, et on donne un point
d’entrée clean à la présenation pour que les lecture-écritures soient
transparentes.

Mon conseil : stocker ça en chaîne, tout le monde sous forme
“pseudo-float”
si ça t’arrange, et faire un truc genre before_save qui va convertir la
valeur, un script du genre :
if value =~ /\d+:\d+/
value[/\d+(?=:)/] + ‘.’ + (value[/:(\d+)/, 1].to_i * 100 / 60).to_s
end

Merci :wink:

Toujours un plaisir de partager.

Michel B.

Merci beaucoup pour ton plaisir de partager alors :wink:

J’aurais même proposé de stocker ça en minutes et donc en integer !
“1.33333…” reste moins joli que “80” à stocker. :slight_smile:

Basecamp (de 37signals) offre la double saisie : “1:30” ou “1.5”. À
l’affichage tout est en flottant à 2 décimales.

Donc je conseillerais dans le modèle, un truc du genre :

def field_in_hours
(read_attribute(:field) || 0) * 60.0
end

def field_in_hours=(value)
value = value.to_s
if value =~ /\d+:\d+/
value = Regexp.last_match(1).to_i * 60 + Regexp.last_match(2).to_i
else
value = value.gsub(/\s+/, ‘’).sub(‘,’, ‘.’).to_f * 60
end
write_attribute(:field, value.round)
end

Et dans la vue :

<%= f.text_field :field_in_hours %>

Au final, on a :field en minutes, et :field_in_hours en heures (format
flottant).

Julien

On 7 juil, 15:59, Michel B. [email protected]

Oops, et sans l’erreur :
if value =~ /(\d+):(\d+)/

Julien