Question Décimales et virgules lors de la saisie d'un nombre dans un formulaire Ruby on Rails


Quel est le meilleur moyen Ruby / Rails pour permettre aux utilisateurs d'utiliser des décimales ou des virgules lors de la saisie d'un nombre dans un formulaire? En d'autres termes, je voudrais que l'utilisateur puisse entrer 2 000,99 et ne pas obtenir 2,00 dans ma base de données.

Existe-t-il une meilleure pratique pour cela?

-- Mettre à jour ---

Est-ce que gsub fonctionne avec des flotteurs ou des bigintegers? Ou est-ce que les rails coupent automatiquement le nombre au moment de la saisie des flottants ou des ints dans un formulaire? J'ai essayé d'utiliser self.price.gsub (",", "") mais j'obtiens "une méthode indéfinie" gsub "pour 8: Fixnum" où 8 est le nombre que j'ai entré dans le formulaire.


12
2018-06-30 21:17


origine


Réponses:


J'ai eu un problème similaire en essayant d'utiliser le contenu localisé dans les formulaires. Localiser la sortie est relativement simple en utilisant ActionView::Helpers::NumberHelper méthodes intégrées, mais l'analyse des entrées localisées n'est pas prise en charge par ActiveRecord.

C'est ma solution, s'il vous plaît, dites-moi si je fais quelque chose de mal. Cela me semble trop simple pour être la bonne solution. Merci! :)

Tout d'abord, ajoutons une méthode à String.

class String
  def to_delocalized_decimal
    delimiter = I18n::t('number.format.delimiter')
    separator = I18n::t('number.format.separator')
    self.gsub(/[#{delimiter}#{separator}]/, delimiter => '', separator => '.')
  end
end

Ensuite, ajoutons une méthode de classe à ActiveRecord::Base

class ActiveRecord::Base
  def self.attr_localized(*fields)
    fields.each do |field|
      define_method("#{field}=") do |value|
        self[field] = value.is_a?(String) ? value.to_delocalized_decimal : value
      end
    end
  end
end

Enfin, déclarons quels champs doivent avoir une entrée localisée.

class Article < ActiveRecord::Base
  attr_localized :price
end

Maintenant, dans votre formulaire, vous pouvez entrer "1.936,27" et ActiveRecord ne générera pas d'erreurs sur un numéro invalide, car il devient 1936.27.


24
2018-02-19 15:51



Voici un code que j'ai copié de Greg Brown (auteur de Ruby Best Practices) il y a quelques années. Dans votre modèle, vous identifiez les éléments "humanisés".

class LineItem < ActiveRecord::Base
  humanized_integer_accessor :quantity
  humanized_money_accessor :price
end

Dans vos modèles de vue, vous devez référencer les champs humanisés:

= form_for @line_item do |f|
  Price:
  = f.text_field :price_humanized

Ceci est conduit par les éléments suivants:

class ActiveRecord::Base
  def self.humanized_integer_accessor(*fields)
    fields.each do |f|
      define_method("#{f}_humanized") do
        val = read_attribute(f)
        val ? val.to_i.with_commas : nil
      end
      define_method("#{f}_humanized=") do |e|
        write_attribute(f,e.to_s.delete(","))
      end
    end
  end

  def self.humanized_float_accessor(*fields)
    fields.each do |f|
      define_method("#{f}_humanized") do
        val = read_attribute(f)
        val ? val.to_f.with_commas : nil
      end
      define_method("#{f}_humanized=") do |e|
        write_attribute(f,e.to_s.delete(","))
      end
    end
  end

  def self.humanized_money_accessor(*fields)
    fields.each do |f|
      define_method("#{f}_humanized") do
        val = read_attribute(f)
        val ? ("$" + val.to_f.with_commas) : nil
      end
      define_method("#{f}_humanized=") do |e|
        write_attribute(f,e.to_s.delete(",$"))
      end
    end
  end
end

7
2017-07-01 07:59



Vous pouvez essayer de supprimer les virgules before_validation ou before_save

Oups, vous voulez faire cela sur le champ de texte avant qu'il ne soit converti. Vous pouvez utiliser un attribut virtuel:

def price=(price)
   price = price.gsub(",", "")
   self[:price] = price  # or perhaps price.to_f
end

2
2018-06-30 21:32



Jetez un oeil à la i18n_alchemy gem pour l'analyse de la date et du numéro et la localisation.

I18nAlchemy a pour but de gérer l'analyse de la date, de l'heure et du nombre, en fonction du format de locale I18n actuel. L'idée principale est que les ORM, tels que ActiveRecord pour l'instant, acceptent automatiquement les dates / numéros donnés dans le format local actuel et renvoient également ces valeurs localisées.


0
2017-09-07 09:06



Je n'ai pas pu implémenter le plus tôt def price=(price) suggestion d'attribut virtuel car la méthode semble s'appeler de manière récursive.

J'ai fini par supprimer la virgule des attributs hash, car comme vous le pensez, ActiveRecord semble tronquer les entrées avec des virgules qui sont placées dans les champs DECIMAL.

Dans mon modèle:

before_validation :remove_comma

def remove_comma
  @attributes["current_balance"].gsub!(',', '')  # current_balance here corresponds to the text field input in the form view

  logger.debug "WAS COMMA REMOVED? ==> #{self.current_balance}"
end

-1
2017-07-24 05:43



Voici quelque chose de simple qui permet de s'assurer que le nombre saisi est correctement lu. La sortie sera toujours avec un point au lieu d'une virgule. Ce n'est pas beau, mais au moins pas critique dans certains cas.

Il nécessite un appel de méthode dans le contrôleur sur lequel vous souhaitez activer le délimiteur de virgule. Peut-être pas parfait en termes de MVC mais assez simple, par exemple:

class ProductsController < ApplicationController

  def create
    # correct the comma separation:
    allow_comma(params[:product][:gross_price])

    @product = Product.new(params[:product])

    if @product.save
      redirect_to @product, :notice => 'Product was successfully created.'
    else
      render :action => "new"
    end
  end

end

L'idée est de modifier la chaîne de paramètres, par exemple:

class ApplicationController < ActionController::Base

  def allow_comma(number_string)
    number_string.sub!(".", "").sub!(",", ".")
  end

end

-1
2018-03-20 10:49