मुद्रा / धन को संभालने का सबसे अच्छा तरीका क्या है?


323

मैं एक बहुत ही बुनियादी शॉपिंग कार्ट सिस्टम पर काम कर रहा हूँ।

मेरे पास एक टेबल itemsहै जिसमें priceटाइप का एक कॉलम है integer

मुझे उन कीमतों के लिए मेरे विचारों में मूल्य मूल्य प्रदर्शित करने में परेशानी हो रही है जिसमें यूरो और सेंट दोनों शामिल हैं। क्या मुझे कुछ स्पष्ट याद आ रहा है, जहां तक ​​रेल की रूपरेखा में मुद्रा को संभालने का संबंध है?


अगर किसी का उपयोग करता है SQL, तो DECIMAL(19, 4) लोकप्रिय पसंद है जाँच यह भी जाँच यहाँ तय करने के लिए कितने दशमलव उपयोग करने के लिए स्थानों, आशा में मदद करता है विश्व मुद्रा प्रारूप।
शैजुत

जवाबों:


495

आप शायद DECIMALअपने डेटाबेस में एक प्रकार का उपयोग करना चाहते हैं । अपने प्रवास में, कुछ इस तरह से करें:

# 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

रेल में, उस :decimalप्रकार को लौटाया जाता है BigDecimal, जो मूल्य गणना के लिए बहुत अच्छा है।

यदि आप पूर्णांक का उपयोग करने पर जोर देते हैं, तो आपको मैन्युअल रूप से और BigDecimalहर जगह से एस में बदलना होगा, जो शायद सिर्फ एक दर्द बन जाएगा।

जैसा कि mcl द्वारा बताया गया है, मूल्य प्रिंट करने के लिए, उपयोग करें:

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

13
उपयोग number_to_currency सहायक, यहां और जानकारी api.rubyonrails.org/classes/ActionView/Helpers/...
mlibby

48
वास्तव में, यह बहुत ही सुरक्षित और आसान है, जो कृत्य_स_डॉलरों के संयोजन में पूर्णांक का उपयोग करता है। क्या आपको कभी फ्लोटिंग-पॉइंट तुलना द्वारा काट लिया गया है? यदि नहीं, तो इसे अपना पहला अनुभव न बनाएं। :) कृत्यों_स_डॉलरों के साथ, आपने 12.34 प्रारूप में सामान रखा, यह 1234 के रूप में संग्रहीत है, और यह 12.34 के रूप में बाहर आता है।
सारा मेई

50
@ सार मेई: बिगडेकिमल्स + दशमलव स्तंभ प्रारूप ठीक से बचा जाता है।
मॉल्फ

114
यह महत्वपूर्ण है कि इस उत्तर को केवल आंख मूंदकर कॉपी न करें - सटीक 8, स्केल 2 आपको अधिकतम 999,999.99 का मूल्य देता है । यदि आपको एक मिलियन से अधिक संख्या की आवश्यकता है, तो सटीक बढ़ाएं!
जॉन केयर्न्स

22
यदि आप अलग-अलग मुद्राओं को संभाल रहे हैं तो केवल 2 के पैमाने का आँख बंद करके उपयोग करना महत्वपूर्ण नहीं है - कुछ उत्तर-अफ्रीकी और अरब मुद्राओं जैसे ओमानी रियाल या ट्यूनीशियाई दिनार में 3 के पैमाने हैं, इसलिए सटीक 8 पैमाने 3 वहाँ अधिक उपयुक्त हैं ।
रिचर्ड्स

117

यहाँ एक अच्छा, सरल तरीका है जो लाभ उठाता है composed_of (ActiveRecord का हिस्सा, ValueObject पैटर्न का उपयोग करके) और धन रत्न का उपयोग करता है

आपको ज़रूरत होगी

  • मनी मणि (संस्करण 4.1.0)
  • एक मॉडल, उदाहरण के लिए Product
  • integerउदाहरण के लिए आपके मॉडल (और डेटाबेस) में एक कॉलम:price

इसे अपनी product.rbफ़ाइल में लिखें :

class Product > ActiveRecord::Base

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

आपको क्या मिलेगा:

  • किसी भी अतिरिक्त बदलाव के बिना, आपके सभी रूप डॉलर और सेंट दिखाएगा, लेकिन आंतरिक प्रतिनिधित्व अभी भी सेंट है। प्रपत्र "$ 12,034.95" जैसे मानों को स्वीकार करेंगे और इसे आपके लिए रूपांतरित करेंगे। आपके विचार में आपके मॉडल या सहायकों के लिए अतिरिक्त हैंडलर या विशेषताएँ जोड़ने की कोई आवश्यकता नहीं है।
  • product.price = "$12.00" स्वचालित रूप से धन वर्ग में परिवर्तित हो जाता है
  • product.price.to_s एक दशमलव स्वरूपित संख्या प्रदर्शित करता है ("1234.00")
  • product.price.format मुद्रा के लिए एक ठीक से स्वरूपित स्ट्रिंग प्रदर्शित करता है
  • यदि आपको सेंट (पेमेंट गेटवे जो पेनीज़ चाहते हैं) भेजने की आवश्यकता है, product.price.cents.to_s
  • मुद्रा रूपांतरण मुफ्त में

14
मुझे इस दृष्टिकोण से प्यार है। कृपया ध्यान दें: सुनिश्चित करें कि इस उदाहरण में 'मूल्य' के लिए आपका माइग्रेशन शून्य और डिफॉल्ट को अनुमति नहीं देता है, ऐसा न हो कि आप यह जानने की कोशिश कर रहे हों कि यह काम क्यों नहीं कर रहा है।
कोरी

3
मुझे money_column रत्न मिला (Shopify से निकाला गया) का उपयोग करने के लिए बहुत सीधा होना चाहिए ... मुद्रा रत्न की तुलना में आसान है, अगर आपको मुद्रा रूपांतरण की आवश्यकता नहीं है।
तांत्रिक

7
यह धन रत्न का उपयोग करने वाले सभी लोगों के लिए ध्यान दिया जाना चाहिए कि रेल कोर टीम की रूपरेखा पर "रचना-रचना" को हटाने और हटाने पर चर्चा कर रही है। मुझे संदेह है कि यदि ऐसा होता है तो इसे संभालने के लिए मणि को अपडेट किया जाएगा, लेकिन यदि आप रेल 4.0 देख रहे हैं तो आपको इस संभावना के बारे में पता होना चाहिए
पीर एलन

1
composed_of यहाँ हटाने के बारे में @ पीरअल्लन की टिप्पणी के बारे में अधिक विवरण के साथ-साथ एक वैकल्पिक कार्यान्वयन भी है।
हर्बसीएसओ

3
इसके अलावा, यह वास्तव में रेल-मनी रत्न का उपयोग करने के लिए आश्वस्त है ।
फॉटेनस

25

मुद्रा को संभालने के लिए सामान्य अभ्यास दशमलव प्रकार का उपयोग करना है। यहाँ "रेल के साथ फुर्तीली वेब विकास" का एक सरल उदाहरण है

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

यह आपको -999,999.99 से 999,999.99 तक की कीमतों को संभालने की अनुमति देगा। आप
अपनी वस्तुओं में एक सत्यापन शामिल करना चाह सकते हैं।

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

अपने मूल्यों की जांच करने के लिए।


1
यह समाधान आपको SQL योग और दोस्तों का उपयोग करने में भी सक्षम बनाता है।
लैरी के

4
क्या आप संभवतः कर सकते हैं: मान्य: मूल्य,: उपस्थिति => सत्य: संख्यात्मकता => {: बृहत्तर_थान => ०}
गैलेक्सी

9

यदि आप Postgres का उपयोग कर रहे हैं (और जब से हम अब 2017 में हैं) आप अपने :moneyकॉलम प्रकार को आजमाना चाहते हैं।

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

7

धन-रत्न रत्न का प्रयोग करें । यह आपके मॉडल में पैसे और मुद्राओं को अच्छी तरह से संभालता है और आपकी कीमतों को प्रारूपित करने के लिए सहायकों का एक समूह है।


हाँ, मैं इससे सहमत हूँ। आम तौर पर, मैं डेटा को मेमोरी में संभालने के लिए इसे सेंट (पूर्णांक) के रूप में संग्रहीत करके एक्ट-ऐस-मनी या मनी (मनी-रेल्स) जैसे रत्न का उपयोग करता हूं। पूर्णांक में इसे संभालना उन बुरा दौर की त्रुटियों को रोकता है। उदाहरण के लिए 0.2 * 3 => 0.6000000000000001 यह, निश्चित रूप से केवल तभी काम करता है जब आपको एक प्रतिशत के अंशों को संभालने की आवश्यकता न हो।
चाड एम

यदि आप रेल का उपयोग कर रहे हैं तो यह बहुत अच्छा है। इसे ड्रॉप करें और दशमलव कॉलम के साथ समस्याओं के बारे में चिंता न करें। यदि आप इसे एक दृश्य के साथ प्रयोग करते हैं, तो यह उत्तर उपयोगी हो सकता है: stackoverflow.com/questions/18898947/…
20

6

बस थोड़ा सा अद्यतन और RoR विकास में कुछ महत्वाकांक्षी कनिष्ठों / शुरुआती लोगों के लिए सभी उत्तरों का एक संयोजन जो निश्चित रूप से कुछ स्पष्टीकरण के लिए यहां आएगा।

धन से काम करना

:decimalDB में पैसे स्टोर करने के लिए उपयोग करें , जैसा कि @molf ने सुझाव दिया (और मेरी कंपनी पैसे के साथ काम करते समय एक सुनहरे मानक के रूप में उपयोग करती है)।

# 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

कुछ बिंदु:

  • :decimalके रूप में इस्तेमाल किया जा रहा है BigDecimalजो कई मुद्दों को हल करता है।

  • precisionऔर scaleजो आप प्रतिनिधित्व कर रहे हैं उसके आधार पर समायोजित किया जाना चाहिए

    • यदि आप भुगतान प्राप्त करने और भेजने के साथ काम करते हैं, precision: 8और scale: 2आपको 999,999.99उच्चतम राशि के रूप में देता है , जो 90% मामलों में ठीक है।

    • यदि आपको किसी संपत्ति या एक दुर्लभ कार के मूल्य का प्रतिनिधित्व करने की आवश्यकता है, तो आपको उच्चतर का उपयोग करना चाहिए precision

    • यदि आप निर्देशांक (देशांतर और अक्षांश) के साथ काम करते हैं, तो आपको निश्चित रूप से उच्चतर की आवश्यकता होगी scale

माइग्रेशन कैसे जनरेट करें

उपरोक्त सामग्री के साथ माइग्रेशन उत्पन्न करने के लिए, टर्मिनल में दौड़ें:

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

या

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

जैसा कि इस ब्लॉग में बताया गया है पोस्ट ।

मुद्रा स्वरूपण

चुंबन अतिरिक्त पुस्तकालयों अलविदा और उपयोग में निर्मित सहायकों। उपयोगnumber_to_currencyसुझाए गए @molf और @facundofarias के रूप में ।

साथ खेलने के लिए number_to_currencyरेल कंसोल में सहायक, के लिए एक कॉल भेजने ActiveSupportकेNumberHelper सहायक एक्सेस करने के लिए वर्ग।

उदाहरण के लिए:

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

निम्नलिखित उत्पादन देता है

2500000,61

Number_to_currency के अन्य optionsकी जाँच करें

इसे कहां लगाना है

आप इसे एक आवेदन सहायक में रख सकते हैं और किसी भी राशि के लिए विचारों के अंदर उपयोग कर सकते हैं।

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

या आप इसे Itemएक उदाहरण विधि के रूप में मॉडल में रख सकते हैं , और इसे कॉल कर सकते हैं जहां आपको मूल्य (विचारों या सहायकों में) को प्रारूपित करने की आवश्यकता है।

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

और, एक उदाहरण कि कैसे मैं number_to_currencyएक कॉन्ट्रोलर के अंदर का उपयोग करता हूं (नोटिस का negative_formatविकल्प, रिफंड का प्रतिनिधित्व करने के लिए उपयोग किया जाता है)

def refund_information
  amount_formatted = 
    ActionController::Base.helpers.number_to_currency(@refund.amount, negative_format: '(%u%n)')
  {
    # ...
    amount_formatted: amount_formatted,
    # ...
  }
end

5

वर्चुअल एट्रीब्यूट्स (संशोधित (भुगतान किया गया) रेलसेक से लिंक) का उपयोग करके आप एक पूर्णांक कॉलम में अपने price_in_cents को स्टोर कर सकते हैं और अपने उत्पाद मॉडल में एक गेट्टर और सेटर के रूप में एक वर्चुअल विशेषता price_in_dollars जोड़ सकते हैं।

# 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

स्रोत: RailsCasts # 016: वर्चुअल एट्रीब्यूट्स : वर्चुअल एट्रिब्यूट्स फॉर्म फील्ड को जोड़ने का एक साफ तरीका है जो सीधे डेटाबेस में मैप नहीं करता है। यहाँ मैं बताता हूँ कि सत्यापन, संघों और बहुत कुछ को कैसे संभालना है।


1
यह 200.0 एक अंक
अजाबरास


2

अगर कोई Sequel का उपयोग कर रहा है तो माइग्रेशन कुछ इस तरह दिखाई देगा:

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

किसी भी तरह सेक्वल अनदेखी: सटीक और: पैमाने

(सीक्वल संस्करण: अगली कड़ी (3.39.0, 3.38.0))


2

मेरे अंतर्निहित API सभी पैसे का प्रतिनिधित्व करने के लिए सेंट का उपयोग कर रहे थे, और मैं इसे बदलना नहीं चाहता था। न ही मैं बड़ी मात्रा में धन के साथ काम कर रहा था। इसलिए मैंने इसे एक सहायक विधि में रखा:

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

यह कम से कम तीन अंकों के साथ पूर्णांक को धर्मान्तरित करता है (यदि आवश्यक हो तो अग्रणी शून्य जोड़ते हुए), फिर अंतिम दो अंकों से पहले एक दशमलव बिंदु सम्मिलित करता है, कभी भी एक का उपयोग करके नहीं Float । वहां से आप अपने उपयोग के मामले में जो भी मुद्रा प्रतीक उपयुक्त हैं जोड़ सकते हैं।

यह निश्चित रूप से त्वरित और गंदा है, लेकिन कभी-कभी यह ठीक है!


विश्वास नहीं कर सकता कि किसी ने आपको नहीं उकसाया। यह केवल एक चीज थी जिसने मेरे मनी ऑब्जेक्ट को अच्छी तरह से एक रूप में प्राप्त करने के लिए काम किया, जैसे कि एक एपीआई इसे ले सकता है। (दशमलव)
कोड-मोनकी

2

मैं इसे इस तरह से उपयोग कर रहा हूं:

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

बेशक कि मुद्रा प्रतीक, सटीक, प्रारूप और इसी तरह प्रत्येक मुद्रा पर निर्भर करता है।


1

आप कुछ विकल्प पास कर सकते हैं number_to_currency(एक मानक रेल 4 दृश्य सहायक):

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

जैसा कि डायलन मार्को ने पोस्ट किया है


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.