Question

Je travaille sur un système de base de panier d'achat.

J'ai une table articles qui a une colonne prix de type entier .

Je ne parviens pas à afficher la valeur du prix dans mes vues pour des prix comprenant à la fois des euros et des centimes d'euro. Me manque-t-il quelque chose d'évident en ce qui concerne le traitement de la monnaie dans le cadre Rails?

Était-ce utile?

La solution

Vous voudrez probablement utiliser un type DECIMAL dans votre base de données. Dans votre migration, procédez comme suit:

# precision is the total number of digits
# scale is the number of digits to the right of the decimal point
add_column :items, :price, :decimal, :precision => 8, :scale => 2

Dans Rails, le type : decimal est renvoyé sous la forme BigDecimal , ce qui est excellent pour le calcul du prix.

Si vous insistez pour utiliser des entiers, vous devrez convertir manuellement vers et à partir de BigDecimal partout, ce qui ne sera probablement plus qu'un problème.

Comme le souligne mcl, pour imprimer le prix, utilisez:

number_to_currency(price, :unit => "€")
#=> €1,234.01

Autres conseils

Voici une approche simple et raffinée qui exploite compound_of (composant d'ActiveRecord, à l'aide du modèle ValueObject) et de la gemme d'argent

.

Vous aurez besoin

  • La bijou d'argent (version 4.1.0)
  • Un modèle, par exemple Produit
  • Une colonne entier dans votre modèle (et votre base de données), par exemple : price

Ecrivez ceci dans votre fichier product.rb :

class Product > ActiveRecord::Base

  composed_of :price,
              :class_name => 'Money',
              :mapping => %w(price cents),
              :converter => Proc.new { |value| Money.new(value) }
  # ...

Ce que vous obtiendrez:

  • Sans modifications supplémentaires, tous vos formulaires afficheront des dollars et des cents, mais la représentation interne ne représente toujours que des cents. Les formulaires accepteront des valeurs telles que " 12 034,95 $ " et le convertir pour vous. Il n'est pas nécessaire d'ajouter des gestionnaires ou des attributs supplémentaires à votre modèle, ni des aides dans votre vue.
  • product.price = " 12,00 $ & <; est automatiquement converti en classe Money
  • product.price.to_s affiche un nombre au format décimal ("1234,00")
  • product.price.format affiche une chaîne correctement formatée pour la devise
  • Si vous devez envoyer des cents (à une passerelle de paiement qui veut des sous), product.price.cents.to_s
  • Conversion de devise gratuite

La pratique courante pour gérer les devises consiste à utiliser un type décimal. Voici un exemple simple tiré de "Développement Web agile avec Rails"

add_column :products, :price, :decimal, :precision => 8, :scale => 2 

Cela vous permettra de gérer des prix allant de -999 999,99 à 999 999,99
Vous pouvez également inclure une validation dans vos éléments, telle que

.
def validate 
  errors.add(:price, "should be at least 0.01") if price.nil? || price < 0.01 
end 

pour vérifier vos valeurs.

Utilisez la bijou Money-rails . Il gère bien l’argent et les devises dans votre modèle et dispose également d’un ensemble d’aides pour formater vos prix.

Si vous utilisez Postgres (et depuis 2017), vous pouvez essayer le type de colonne : money .

add_column :products, :price, :money, default: 0

En utilisant Attributs virtuels (lien vers le Railscast révisé (payant)) , vous pouvez stocker vos price_in_cents dans colonne entière et ajoutez un attribut virtuel price_in_dollars dans votre modèle de produit en tant que getter et setter.

# Add a price_in_cents integer column
$ rails g migration add_price_in_cents_to_products price_in_cents:integer

# Use virtual attributes in your Product model
# app/models/product.rb

def price_in_dollars
  price_in_cents.to_d/100 if price_in_cents
end

def price_in_dollars=(dollars)
  self.price_in_cents = dollars.to_d*100 if dollars.present?
end

Source: RailsCasts # 016: attributs virtuels : Les attributs virtuels constituent un moyen simple d’ajouter des champs de formulaire qui ne sont pas directement mappés à la base de données. Je montre ici comment gérer les validations, les associations et plus encore.

Certainement nombres entiers .

Et même si BigDecimal existe techniquement, 1.5 vous donnera toujours un flottant pur en Ruby.

Si quelqu'un utilise Sequel, la migration ressemblerait à quelque chose comme:

add_column :products, :price, "decimal(8,2)"

en quelque sorte, Sequel ignore: precision et: scale

(Version de la suite: suite (3.39.0, 3.38.0))

Je l'utilise de cette façon:

number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")

Bien entendu, le symbole monétaire, la précision, le format, etc., dépendent de chaque devise.

Vous pouvez transmettre certaines options à number_to_currency (aide de la vue standard de Rails 4):

number_to_currency(12.0, :precision => 2)
# => "$12.00"

Publié par Dylan Markow

Mes API sous-jacentes utilisaient toutes des centimes pour représenter de l'argent, et je ne voulais pas changer cela. Je ne travaillais pas non plus avec de grosses sommes d'argent. Donc, je viens de mettre cela dans une méthode d'assistance:

sprintf("%03d", amount).insert(-3, ".")

Cela convertit l'entier en une chaîne d'au moins trois chiffres (en ajoutant des zéros à gauche si nécessaire), puis insère un point décimal avant les deux derniers chiffres, en n'utilisant jamais de Float . À partir de là, vous pouvez ajouter les symboles de devise appropriés à votre cas d'utilisation.

C'est certainement rapide et sale, mais parfois c'est très bien!

Code simple pour Ruby & amp; Rails

<%= number_to_currency(1234567890.50) %>

OUT PUT => $1,234,567,890.50

Juste une petite mise à jour et une cohésion de toutes les réponses pour certains aspirants débutants / débutants dans le développement de RoR qui viendront sûrement ici pour quelques explications.

Travailler avec de l'argent

Utilisez : decimal pour stocker de l'argent dans la base de données, comme @molf l'a suggéré (et ce que ma société utilise comme norme de référence lorsque vous travaillez avec de l'argent).

# precision is the total number of digits
# scale is the number of digits to the right of the decimal point
add_column :items, :price, :decimal, precision: 8, scale: 2

Quelques points:

  • : le séparateur décimal sera utilisé comme BigDecimal , qui résout de nombreux problèmes.

  • précision et échelle doivent être ajustés en fonction de ce que vous représentez

    • Si vous travaillez avec la réception et l'envoi de paiements, la précision : 8 et : 2 vous donne 999 999,99 comme montant le plus élevé. , ce qui est bien dans 90% des cas.

    • Si vous devez représenter la valeur d'une propriété ou d'une voiture rare, vous devez utiliser une précision supérieure.

    • Si vous travaillez avec des coordonnées (longitude et latitude), vous aurez sûrement besoin d'une échelle plus élevée.

Comment générer une migration

Pour générer la migration avec le contenu ci-dessus, exécutez-le dans le terminal:

bin/rails g migration AddPriceToItems price:decimal{8-2}

ou

bin/rails g migration AddPriceToItems 'price:decimal{5,2}'

comme expliqué dans ce blog post.

Formatage de la devise

BAISER les bibliothèques supplémentaires au revoir et utiliser les assistants intégrés. Utilisez number_to_currency comme suggéré par @molf et @facundofarias.

Pour jouer avec l’assistant number_to_currency dans la console Rails, envoyez un appel à la classe ActiveSupport de NumberHelper afin d’accéder à l’aide.

Par exemple:

ActiveSupport::NumberHelper.number_to_currency(2_500_000.61, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")

donne le résultat suivant

2500000,61€

Vérifiez les autres options de number_to_currency . assistant.

Où le mettre

Vous pouvez le placer dans un assistant d'application et l'utiliser dans toutes les vues.

module ApplicationHelper    
  def format_currency(amount)
    number_to_currency(amount, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
  end
end

Vous pouvez également l'insérer dans le modèle Article en tant que méthode d'instance et l'appeler à l'endroit où vous devez formater le prix (en vues ou en assistants).

class Item < ActiveRecord::Base
  def format_price
    number_to_currency(price, unit: '€', precision: 2, separator: ',', delimiter: '', format: "%n%u")
  end
end

Et un exemple d'utilisation du number_to_currency dans un contrôleur (notez l'option negative_format utilisée pour représenter les remboursements)

def refund_information
  amount_formatted = 
    ActionController::Base.helpers.number_to_currency(@refund.amount, negative_format: '(%u%n)')
  {
    # ...
    amount_formatted: amount_formatted,
    # ...
  }
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top