Changer le format DATE dans to_xml

Il existe plusieurs formats Date prédéfinis, que l’on peut compléter
si nécessaire :

ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS
=> {:db=>"%Y-%m-%d %H:%M:%S", :rfc822=>"%a, %d %b %Y %H:%M:%S
%z", :short=>"%d %b %H:%M", :long=>"%B %d, %Y %H:%M"}

Exemple d’usage :

now = Time.now
now = Time.now
=> Thu Aug 30 11:47:07 +0200 2007

now.to_s(:db)
now.to_s(:db)
=> “2007-08-30 11:47:07”

Comment puis-je dire à la fonction to_xml (quitte à en modifier le
code) qu’elle génère les Dates dans le format souhaité ?

Merci,

Christophe.

Christophe a écrit :

now = Time.now
=> Thu Aug 30 11:47:07 +0200 2007

now.to_s(:db)
now.to_s(:db)
=> “2007-08-30 11:47:07”

Comment puis-je dire à la fonction to_xml (quitte à en modifier le
code) qu’elle génère les Dates dans le format souhaité ?

En modifiant temporairement le hash Hash::XML_FORMATTING :

def my_xml_serialization
old_proc = Hash::XML_FORMATTING[‘datetime’]
Hash::XML_FORMATTING[‘datetime’] = Proc.new { |datetime|
datetime.to_s(:rfc822) }

result = yield if block_given ?

Hash::XML_FORMATTING[‘datetime’] = old_proc
result
end

Garanti 100% non
testé.
– Jean-François.


Ruby ( http://www.rubyfrance.org ) on Rails ( http://www.railsfrance.org
)

Oui, j’étais en train de me demander comment modifier XML_FORMATTING
sans pour autant modifier conversions.rb.

Je vais donc essayer ta méthode ; juste une question pour le débutant
RoR que je suis :

La ligne “result = yield if block_given ?”, c’est du code ou du pseudo-
code ? Dans ce dernier cas, est-ce que j’y mets mon code contenu dans
la fonction suivante (qui appelle to_xml ) ?

def list_timespan_xml
@rv_wrk_medical_consultations = RvWrkMedicalConsultation.find(
:all, :conditions =>
[ “start_date >= ? and end_date <= ?”,

params[:start_date], params[:end_date]])
render :xml => @rv_wrk_medical_consultations.to_xml
end

Merci pour ton aide,

Christophe.

Jean-François,

J’ai testé et ça a l’air de marcher ! Tu me sors une épine du pied. Je
vais maintenant définir un nouveau format dans environment.rb via
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!
(). Merci encore,

Christophe.

P.S. : voici ma nouvelle fonction :

def list_timespan_flexdateformat_xml
old_proc = Hash::XML_FORMATTING[‘datetime’]
Hash::XML_FORMATTING[‘datetime’] = Proc.new { |datetime|
datetime.to_s(:rfc822) }

@rv_wrk_medical_consultations = RvWrkMedicalConsultation.find(
                                  :all, :conditions =>

[ “start_date >= ? and end_date <= ?”,

params[:start_date], params[:end_date]])
render :xml => @rv_wrk_medical_consultations.to_xml

Hash::XML_FORMATTING['datetime'] = old_proc

end

Christophe :

Je vais donc essayer ta méthode ; juste une question pour le débutant
RoR que je suis :

La ligne “result = yield if block_given ?”, c’est du code ou du
pseudo-code ?

c’est du pseudo-code, car normalement ça devrait être
result = yield if block_given?
:slight_smile:

C’était pour une utilisation avec un bloc de code (dans le
cas où la valeur retournée par le block est importante, donc
nécéssité de le stocker dans result)

C’est dans le cadre d’une modification temporaire.

Si ton modèle RvWrkMedicalConsultation, euh… on va supposer
que c’est le modèle Article :slight_smile:
si la sérialisation XML se fait toujours de la même manière,
autant le mettre dans le modèle :

class Article < AR::B
def to_xml(options= {})
old_proc = Hash::XML_FORMATTING[‘datetime’]
# ouais je me suis aperçu après que le sujet du thread parlait de date
# mais le principe est le même
Hash::XML_FORMATTING[‘datetime’] = Proc.new { |datetime|
datetime.to_s(:rfc822) }
result = super
Hash::XML_FORMATTING[‘datetime’] = old_proc
result
end
end

Dans ce cas-là le code du contrôleur est
inchangé.
On suppose que tous les champs datetime (ou date) sont
traitésà la même enseigne.

Mais après réflexion, ce code est assez bourrin, car si jamais
tu inclus des associations dans ton article, il y a des effets de bord.

C’est gênant ou pas.

Je vois 2 manières d’y remédier.

  • écrire sa propre classe XmlSerializer qui dériverait de
    AR::XmlSerialization::XmlSerialize et dériver aussi
    AR::XmlSerialization::XmlSerialize::Attribute
    et de surcharger les méthodes qui vont bien
    (#serializable_attributes et # compute_value normalement).

  • monkey patcher
    AR::XmlSerialization::XmlSerialize::Attribute#compute_value
    pour écrire un truc du genre :

if formatter = @record.class.xml_formatting[type.to_s]

avec une variable de classe :

class AR::B
cattr_accessor :xml_formatting, :instance_writer => false
@@xml_formatting = Hash::XML_FORMATTING
end

en fait non. Une variable d’instance de classe, ce serait mieux.

Enfin bref.

2e mail :

def list_timespan_flexdateformat_xml

Hash::XML_FORMATTING['datetime'] = old_proc

end

Si tu fais ça temporairement dans le contrôleur, ce serait peut-être
plus élégant d’en faire un around_filter :

around_filter :my_serialization, :only =>
:list_timespan_flexdateformat_xml

private
def my_xml_serialization
old_proc = Hash::XML_FORMATTING[‘datetime’]
Hash::XML_FORMATTING[‘datetime’] = Proc.new { |datetime|
datetime.to_s(:rfc822) }

yield

Hash::XML_FORMATTING[‘datetime’] = old_proc
end

Et le code de ton action est inchangé par rapport au post initial.
(et le filtre réutilisable) (pas testé).

-- Jean-François.


membre du CA de Ruby France.
Ruby ( http://www.rubyfrance.org ) on Rails ( http://www.railsfrance.org
)

On 8/31/07, gers32 [email protected] wrote:

Mon employeur me demande de créer un “proof of concept” basé sur RoR
et Flex, avant de me pencher sérieusement sur les bouquins. Du coup,
mes connaissances sont trop limitées pour essayer tes solutions plus
“propres”… pour l’instant. Je vais donc en rester là (j’ai parlé de
date, mais il s’agissait bien de datetime…) ; en revanche, j’ai un
petit souci lié à une particularité de la base Oracle :

Pas vraiment une réponse direct à ton problème mais à la prochaine rails
conf de berlin il y a un tutorial d’une demi journée sur Rails+flex,
pour
une société c’est clairement une bonne occaz de te former à bas prix
plutôt
que de te laisser trainer sur ce genre de problème.
http://www.railsconfeurope.com/pub/w/61/tutorials.html

Pour résumer : dans le XML, les champs Oracle DATE sont formatés par

défaut :
<start_date type=“datetime”>2007-08-23T00:00:00+02:00</start_date>

Et en appliquant ta solution, lorsqu’elle marche (ça dépend du format)
par exemple avec ‘%Y %m %d’, ‘%Y/%m/%d’ ou ‘%Y-%m-%d’, j’obtiens
toujours :
<start_date type=“datetime”>2007-08-23</start_date>

Sinon pour une réponse plus directe si ca change c’est que ca marche
quelque
part :). Donc soit tu n’as pas restarté le serveur quand il fallait,
soit tu
n’as pas passé les bons arguments, typiquement la method derrière la
scène
c’est DateTime.strftime ou Time.strftime :slight_smile:

A mon humble avis tu as juste oublié de restarté,
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS n’est pas
chargé à chaque fois pas plus que environnement.rb même en mod dev, my
$0.02

Renaud

Mon employeur me demande de créer un “proof of concept” basé sur RoR
et Flex, avant de me pencher sérieusement sur les bouquins. Du coup,
mes connaissances sont trop limitées pour essayer tes solutions plus
“propres”… pour l’instant. Je vais donc en rester là (j’ai parlé de
date, mais il s’agissait bien de datetime…) ; en revanche, j’ai un
petit souci lié à une particularité de la base Oracle :

En effet, j’ai des champs de type DATE ; certains contiennent l’heure,
d’autres non. Or, la solution marche avec les premiers, mais pas avec
les seconds… Pour remédier à ce problème lors de l’affichage dans
les vues générées par Rails, j’ai remplacé “datetime_select” par
“date_select” dans _form.rhtml. Mais pour ce qui est de mon XML,
remplacer “datetime” par “date” dans list_timespan_flexdateformat_xml
ne change rien.

Pour résumer : dans le XML, les champs Oracle DATE sont formatés par
défaut :
<start_date type=“datetime”>2007-08-23T00:00:00+02:00</start_date>

Et en appliquant ta solution, lorsqu’elle marche (ça dépend du format)
par exemple avec ‘%Y %m %d’, ‘%Y/%m/%d’ ou ‘%Y-%m-%d’, j’obtiens
toujours :
<start_date type=“datetime”>2007-08-23</start_date>

Or, ce format ne convient pas au parseur Flex. Bien sûr, je peux
toujours le parser moi-même dans Flex, mais ce mystère me préoccupe.

Christophe.

On Aug 30, 4:05 pm, “Jean-François Trân” [email protected]

Sinon pour une réponse plus directe si ca change c’est que ca marche quelque
part :). Donc soit tu n’as pas restarté le serveur quand il fallait, soit tu
n’as pas passé les bons arguments, typiquement la method derrière la scène
c’est DateTime.strftime ou Time.strftime :slight_smile:

A mon humble avis tu as juste oublié de restarté,
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS n’est pas
chargé à chaque fois pas plus que environnement.rb même en mod dev, my $0.02

Renaud

J’ai bien redémarré le serveur à chaque fois, sinon, je n’aurais pas
obtenu “2007-08-23” à la place de “2007-08-23T00:00:00+02:00” (même si
ce n’est pas le résultat escompté…). Je pense que le problème est
plus subtil, car le même champ DATE me posait problème dans les
formulaires RHTML auto-générés : j’ai dû remplacer “datetime_select”
par “date_select” dans _form.rhtml à cause du message d’erreur
“private method `min’ called for #<Date: 4907537/2,0,2299161>” alors
que ça fonctionnait très bien pour l’autre champ DATE…

Christophe.

J’ai bien redémarré le serveur à chaque fois, sinon, je n’aurais pas
obtenu “2007-08-23” à la place de “2007-08-23T00:00:00+02:00” (même si
ce n’est pas le résultat escompté…). Je pense que le problème est
plus subtil, car le même champ DATE me posait problème dans les
formulaires RHTML auto-générés : j’ai dû remplacer “datetime_select”
par “date_select” dans _form.rhtml à cause du message d’erreur
“private method `min’ called for #<Date: 4907537/2,0,2299161>” alors
que ça fonctionnait très bien pour l’autre champ DATE…

Dans ce cas il va falloir te salir les mains et sortir le debugger où au
moins lancer la trace sur l’utilisation des strftime car personne ne
pourra
t’en dire plus sans accès au code. Imho c’est la bonne occaz pour
construire
les tests histoire d’isoler les éléments en cause.