Ouverture de session

Commentaires récents

Syndication
Flux XML

datetime_select et choix des alternatif des heures

datetime_select et choix des alternatif des heures
Posté par guillaume hammadi le Lundi, 7 Juillet, 2008 - 5:40pm. Débuter avec Rails

Bonjour,
Pour un système dans lequel un utilisateur peut enregistrer des "absences" allant d'une date A à une date B, j'utilise actuellement un assistant datetime_select brut de framework. Hors, j'aimerais pouvoir remplacer les select d'heure et minute par 3 choix uniques : matin, midi et soir.
J'essaie d'utiliser pour ce faire trois boutons radio.

Je n'ai pour l'instant pas de résultats satisfaisants, l'absence n'est jamais enregistrée. J'ai essayé de passer des paramètres cachés dans le formulaire en utilisant disable_hour => true, pour tester, mais dans ce cas-là le validateur du modèle me jette. J'ai aussi envisagé d'utiliser un builder perso pour le formulaire, mais devant la complexité (apparente ?) de cette méthode, j'ai plus insisté sur des contournements.

Quelle est la manière élégante de procéder ? Si c'est vraiment dans la logique des choses de passer par un absence_builder, et bien je prendrai le temps nécessaire...



[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | sujet précédent | sujet suivant | envoyer par email ]

Options d'affichage des commentaires
Sélectionnez la méthode d'affichage des commentaires que vous préférez, puis cliquez sur "Sauvegarder" pour activer vos changements.

Sujet: 
Savoir ce que tu veux
Auteur: 
jasperiel
Date: 
Lun, 07/07/2008 - 19:12

> j'aimerais pouvoir remplacer les select d'heure et minute par 3
> choix uniques : matin, midi et soir.

Parfait, mais comment ?
Que veux-tu stocker dans ta BDD ?
Est-ce qu'un champ "date" plus un champ (euh, disons "créneau") te suffirait ou est-ce hors de question ? C'est peut-être plus simple, et Rails te génèrera tout tout seul.

> Je n'ai pour l'instant pas de résultats satisfaisants,
> l'absence n'est jamais enregistrée.
Avec quel message d'erreur ?

> J'ai essayé de passer des paramètres cachés dans le formulaire
> en utilisant disable_hour => true, pour tester,
Avec quel code ?

> mais dans ce cas-là le validateur du modèle me jette.
Avec quelle erreur ?

> J'ai aussi envisagé d'utiliser un builder perso pour le formulaire,
> mais devant la complexité (apparente ?) de cette méthode,

Il suffit de savoir ce que tu veux et où : que faire et quand le faire apparaîtront ensuite plus facile à trouver, car les choix seront restreints.

Par exemple, faire trois radio buttons est facile :
fais un helper et utilise les actionView.
Le seul souci ensuite, si tu gardes un champ datetime, c'est de convertir l'heure en valeur (à faire dans le contrôleur de EDIT et NEW histoire que tes radio buttons aient la valeur appropriée) puis la valeur en heure quand ton formulaire est soumis (CREATE et UPDATE).

Ce n'est que deux helpers d'une ligne chacun en private dans ton contrôleur (ou mieux : des méthodes dans ton modèle), et penser à les appeler dans les 4 méthodes que je t'ai dites. Il faudra juste que tu penses à regarder le code généré et tes paramètres pour savoir comment faire proprement.

> Quelle est la manière élégante de procéder ?
Définis ton besoin, regarde ce qui est propre, code-le, et teste-le.


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Merci pour ta réponse. Je
Auteur: 
guillaume hammadi
Date: 
Lun, 07/07/2008 - 22:50

Merci pour ta réponse. Je sais que je veux garder un datetime, car dans d'autres circonstances d'utilisation, la saisie de l'heure est importante.

Je regarde plus en détails dans la journée demain pour répondre plus point par point.


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
après un peu de tri...
Auteur: 
guillaume hammadi
Date: 
Mar, 08/07/2008 - 16:26

J'ai un peu fait le ménage. La solution sur laquelle je planche est la suivante. Dans la vue "new" :

...
f.datetime_select :begin_date, :order => [:day, :month, :year], :discard_hour => true

p'tit dej' input type='radio' name='begin_date_slot' value='breakfast'
midi input type='radio' name='begin_date_slot' value='lunch'
soir input type='radio' name='begin_date_slot' value='dinner'

Pareil pour end_date.

Puis dans l'action create du contrôleur, j'essaie de modifier l'heure de l'absence :


#les configurations sont des objets de BD
#permettant de stocker des paramètres
#transversaux à certains objets.
@configuration = Configuration.find:first

@absence = Absence.new(params[:absence])
begin_date_slot = params[:begin_date_slot]
end_date_slot = params[:end_date_slot]

case begin_date_slot
when 'breakfast'
@absence.begin_date.hour = @configuration.breakfastTime
when 'lunch'
@absence.begin_date.hour = @configuration.lunchTime
when 'dinner'
@absence.begin_date.hour = @configuration.dinnerTime
else
@absence.begin_date.hour = "00"
end

case end_date_slot
when 'breakfast'
@absence.end_date.hour = @configuration.breakfastTime
when 'lunch'
@absence.end_date.hour = @configuration.lunchTime
when 'dinner'
@absence.end_date.hour = @configuration.dinnerTime
else
@absence.end_date.hour = "00"
end

Le soucis (entre autre ?) c'est que je n'ai pas de setter pour l'heure d'un objet de classe Time. Dois-je en créer un à la main ?

Le message d'erreur, dans l'état actuel des choses, est le suivant :


NoMethodError (You have a nil object when you didn't expect it!
The error occurred while evaluating nil.hour=):


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
un peu de factorisation
Auteur: 
jasperiel
Date: 
Mer, 09/07/2008 - 12:02

Voilà, c'est effectivement comme ça que je vois les choses.
Par contre, soyons DRY, factorisons le code !

ETAPE 1 : au lieu de répéter @absenceblabla = blabla, tu peux faire
@truc = case machin ...

ETAPE 2 : au lieu de répéter le case, tu peux le mettre dans une fonction, par exemple "slot2time" (slot to time, d'un "slot" vers un vrai "time"). Tu feras ensuite une ou deux lignes de code, @machin_debut, @machin_fin = slot2time(truc_debut), slot2time(truc_fin)

ETAPE 3 : le faire dans le create ne suffit pas, il te faudra l'update aussi. Fais donc une fonction qui contiendra les deux lignes de l'appel à slot2time ci-dessus, plus toute autre logique du genre, que tu peux appeler convert_data ou convert_params par exemple.

Pour le bug, bin il est très simple : le log te dit que @absence.end_date n'existe pas, donc ça n'a pas de sens de lui donner une heure.
Tu n'as plus qu'à choisir entre convertir dès le début les paramètres (sous forme de hash, loggue params.inspect pour comprendre le principe) en "bons" paramètres (ça te permettra de dégager les données inutiles en prime) ou de créer l'objet puis de modifier ses propriétés. La doc des classes Date, Time et DateTime t'aidera mieux que moi.


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Solution !
Auteur: 
guillaume hammadi
Date: 
Mer, 09/07/2008 - 16:15

C'est bon, c'est réglé.
Contrôleur :
def create
@configuration = Configuration.find:first
@absence = Absence.new(params[:absence])

if @absence.save
... (code classique)

Vue new

% form_for([:colocation, @absence]) do |form| %>
%= form.hidden_field :colocataire_id, :value => params[:colocataire_id] %>

Du
%= form.datetime_select :begin_date, :order => [:day, :month, :year], :discard_hour => true %>

Créneau de départ
%= render :partial => 'slot', :locals => {:moment => "begin", :form => form } %>

...(pareil pour le Retour)

Le partiel slot

petit déjeuner %= input type='radio' name="absence[ %= moment %>_date(4i)]" value=" %= @configuration.breakfastTime %>" />
midi input type='radio' name="absence[ %= moment %>_date(4i)]" value=" %= @configuration.lunchTime %>" />
soir input type='radio' name="absence[ %= moment %>_date(4i)]" value=" %= @configuration.dinnerTime %>" />
%= form.hidden_field moment + "_date(5i)", :value => "00" %>

Tout ceci fonctionne (il me reste encore le update à faire, avec quelques factorisations faciles).
Le truc compliqué, c'était de trouver la syntaxe pour insérer au milieu des paramètres des données pour que mon @absence n'y voie que du feu, ce qui me permet ensuite de ne pas avoir à faire de conversion dans le contrôleur.

En revanche, je n'ai pas réussi à faire tourner le partiel avec des assistants de bouton radio:

%= form.radio_button :absence["begin_date(4i)"], @configuration.lunchTime %>
%= form.radio_button :absence[:begin_date(4i)], @configuration.lunchTime %>
%= form.radio_button :absence => :begin_date(4i), @configuration.lunchTime %>
etc.

J'ai essayé plusieurs combinaisons. Je n'ai pas trouvé de doc précise sur ce point, et l'erreur est toujours un problème de syntaxe quand le parser tombe sur la parenthèse ouvrante après begin_date.

les paramètres d'une absence qui est sauvée correctement ressemblent à ça:
Parameters: {"absence"=>{"end_date(3i)"=>"12", "end_date(4i)"=>"22", "colocataire_id"=>"1", "end_date(5i)"=>"00", "begin_date(1i)"=>"2008", "begin_date(2i)"=>"7", "begin_date(3i)"=>"11", "begin_date(4i)"=>"8", "begin_date(5i)"=>"00", "description"=>"premier vrai test", "end_date(1i)"=>"2008", "end_date(2i)"=>"7"}, "commit"=>"Ajouter", "colocation_id"=>"1", "authenticity_token"=>"e1c7aa4cbe39877b992603a6745caeb2d6231069", "action"=>"create", "controller"=>"absences"}

Une idée pour que ça marche ? Une voie de factorisation plus pertinente ?


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
quoting
Auteur: 
jasperiel
Date: 
Mer, 09/07/2008 - 17:06

> l'erreur est toujours un problème de syntaxe quand le parser tombe
> sur la parenthèse ouvrante après begin_date.

Bin, passe ton paramètre dans une string, ou joue avec toutes les formes de quoting possible (avec les backslashes, ou pire avec le %q si t'as vraiment plus le choix).


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Nouveaux liens

Qui est en ligne
Il y a actuellement 1 utilisateur et 14 invités en ligne.

railsfrance.org - communauté francophone des utilisateurs de Ruby on Rails
[ Propulsé par Drupal ]