2009-02-26 8 views
29

Je souhaite que les champs de formulaire d'édition soient aussi conviviaux que possible. Par exemple, pour les valeurs numériques, je voudrais que le champ soit affiché avec des virgules (comme number_with_precision).Comment puis-je formater la valeur affichée dans un champ d'édition Rails?

C'est assez facile du côté de l'affichage, mais qu'en est-il de l'édition? Y at-il un bon moyen de le faire? J'utilise le Rails FormBuilder. Après enquête, j'ai trouvé qu'il utilise InstanceTag, qui obtient les valeurs pour les champs en utilisant <attribute>_value_before_type_cast ce qui signifie que <attribute> ne sera pas appelé.

+0

J'ai commencé une prime sur cette question parce que je veux savoir s'il y a un meilleure réponse que celles exprimées par JDL et moi-même. Avoir à cela! –

Répondre

37

Le meilleur que je suis venu avec à ce jour est quelque chose comme ceci:

<%= f.text_field :my_attribute, :value => number_with_precision(f.object.my_attribute) %> 

Ou my_attribute pourrait retourner la valeur formatée, comme ceci:

def my_attribute 
    ApplicationController.helpers.number_with_precision(read_attribute(:my_attribute)) 
end 

Mais vous devez toujours utiliser :value

<%= f.text_field :my_attribute, :value => f.object.my_attribute %> 

Cela semble beaucoup de travail.

+0

Remarque: Si vous utilisez la première solution avec un format qui ajoute des virgules ou des symboles monétaires, vous devez les supprimer dans les méthodes create et update de votre contrôleur. – LeBleu

+0

J'éviterais d'utiliser la deuxième solution, référencer 'ApplicationController' depuis votre modèle n'est certainement pas une bonne chose à prendre l'habitude de le faire. –

+0

Le dernier fonctionnait mieux pour moi, mes fonctions pouvaient encore être dans mon modèle de données et cela n'affecte pas la soumission ou l'édition. Belle solution! –

9

Je préfère votre première réponse, la mise en forme étant effectuée dans la vue. Toutefois, si vous souhaitez effectuer la mise en forme dans le modèle, vous pouvez utiliser des méthodes wrapper pour le getter et le setter, et éviter d'avoir à utiliser entièrement l'option: value.

Vous finiriez avec quelque chose comme ça.

def my_attribute_string 
    foo_formatter(myattribute) 
end 

def my_attribute_string=(s) 
    # Parse "s" or do whatever you need to with it, then set your real attribute. 
end 

<%= f.text_field :my_attribute_string %> 

Railscasts couvert cela avec un objet dans un temps text_field à episode #32. La partie vraiment intelligente de ceci est comment ils manipulent des erreurs de validation. Cela vaut la peine de regarder l'épisode pour ça seul.

3

Si vous voulez qu'un format soit créé ou maintenu pendant l'édition, vous devrez ajouter du Javascript pour implémenter des "masques". Here is a demo.

Il s'agit du premier hit de these results.

+0

Demo est plus là, voici une nouvelle: https://igorescobar.github.io/jQuery-Mask-Plugin/ – fatfrog

1

J'ai fait quelque chose de similaire. Nous formons les heures et les longueurs en utilisant un générateur de formulaire personnalisé. Il utilise la text_field existante, mais il enveloppe de sorte que la valeur peut être personnalisée:

class SuperFormBuilder < ActionView::Helpers::FormBuilder 
    include ApplicationHelper 
    include FormHelper 
    include ActionView::Helpers::TagHelper 
    include ActionView::Helpers::FormTagHelper 

    def length_field(label,*args) 
    scale = 'medium' 
    args.each do |v| 
     if v.has_key?(:scale) 
     scale = v[:scale] 
     v.delete(:scale) 
     end 
    end 
    value = length_conversion(@object.send(label.to_sym),scale) 
    options = (args.length > 0) ? args.pop : {} 
    return has_error(label, text_field_tag(field_name(label),value,*args) + ' ' + length_unit(scale)) 
end 

private 
def field_name(label) 
    return @object_name + "[#{label}]" 
end 

def has_error(label, output) 
    return "<div class='fieldWithErrors'>#{output}</div>" if @object.errors[label] 
    return output 
end 

Et il est utilisé comme ceci:

<%= form_for(@section, {:action => 'save', :id => @section.id}, :builder => SuperFormBuilder) do |sf| %> 
    <%= sf.length_field :feed_size_min_w, :size => 3, :scale => 'small' %> 
<% end %> 

Le résultat final est une valeur dans l'unité appropriée en fonction hors de leur choix sur le système (métrique, impérial) et l'échelle IE petit = pouces ou millimètres.

J'ai fondamentalement copié la méthode text_field du constructeur de formulaire existant, qui utilise lui-même la balise text_field_tag.

Il y a deux gotchas: 1) Connaître le nom du champ d'objet et comment accéder à l'objet pour obtenir la valeur que vous voulez formater. 2) Obtenir le bon nom, donc quand le formulaire est soumis, il fait partie du hash params correct.

Le générateur de formulaire reçoit une variable de classe @object. Vous pouvez obtenir la valeur du champ en utilisant la méthode .send.Dans mon cas, j'envoie l'étiquette: feed_size_min_w à l'objet @object et récupère sa longueur. Je le convertis ensuite au format désiré et je le donne à text_field_tag.

Le nom du champ est la clé pour qu'il finisse dans le hash de params, dans mon exemple les params [: sections] one. J'ai fait une petite fonction d'assistance appelée field_name qui s'occupe de ça.

Enfin, le has_error enveloppe le champ dans un div d'erreur s'il y a des erreurs sur cette étiquette.

3

Vous pouvez utiliser le plug-in number_format. En spécifiant un number_format pour un attribut numérique existant dans votre modèle, l'attribut apparaîtra désormais comme formaté pour Rails dans tous les formulaires et toutes les vues. Il sera également analysé à partir de ce format (lorsqu'il est assigné via des formulaires) avant l'insertion dans la base de données. (Le plugin crée également unformatted_<attribute-name> purement numériques accesseurs qui peuvent continuer à être utilisés pour l'arithmétique, ou pour l'attribution numérique directe ou la récupération par vous pour une intégration transparente.)

class MyModel < ActiveRecord::Base 
    # this model has the balance attribute, which we 
    # want to display using formatting in views, 
    # although it is stored as a numeric in the database 
    number_format :balance, 
       :precision => 2, 
       :delimiter => ',', 
       :strip_trailing_zeros => false 

    def increment_balance 
    unformatted_balance += 10 
    end 

Vous pouvez également combiner ci-dessus avec une solution Javascript, ce qui peut forcer l'utilisateur à maintenir le point décimal et les séparateurs de milliers en place lors de l'édition, bien que ce ne soit pas vraiment nécessaire.

+0

Bonne idée. Ne fonctionne pas sur Rails 3 comme je l'ai testé aujourd'hui. – Cheng

4

Ceci est une vieille question, mais au cas où quelqu'un trouverait cela, vous pourriez utiliser les helpers number_to_X. Ils ont tous les attributs que vous pourriez jamais vouloir pour afficher votre valeur d'édition:

<%= f.text_field :my_number, :value => number_to_human(f.object.my_number, :separator => '', :unit => '', :delimiter => '', :precision => 0) %> 

Il y a plus d'attributs aussi disponibles: http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html

Questions connexes