I'm trying use the gem money-rails but with no success.
I live in Brazil and here the decimal mark is "," and the thousand separator is "."
So, I add the follow code in a money.rb initializer:
MoneyRails.configure do |config|
config.default_currency = :brl
config.register_currency = {
:id => :brl,
:priority => 1,
:iso_code => "BRL",
:name => "Real",
:symbol => "R$",
:symbol_first => true,
:subunit => "Cent",
:subunit_to_unit => 100,
:thousands_separator => ".",
:decimal_mark => ","
}
end
And in my model class "Produto":
class Produto < ApplicationRecord
attr_accessor :nome, :preco
monetize :preco_centavos
end
But when I try use this in Rails console I get a different behavior:
irb(main):001:0> p = Produto.new
=> #<Produto id: nil, nome: nil, preco_centavos: 0, preco_currency: "BRL", created_at: nil, updated_at: nil>
irb(main):002:0> p.preco = 1000.to_money
=> #<Money fractional:100 currency:BRL>
irb(main):003:0> p.preco.format
=> "R$1,000.00"
The format method return "R$1,000.00" when I expect "R$1.000,00".
Someone already passed for this?
PS: Sorry for my bad English
This is a bug (or at least a misleading feature) in the money-rails gem code. Set Money.use_i18n = false. Once you do this, then you won't need to do config.register_currency for the commas/decimals, at least. 1000.to_money('BRL').format yields "R$1.000,00".
See https://github.com/RubyMoney/money-rails/blob/4a35ae823843fba80c036e2332e80d6b9e06dcb5/lib/money-rails/active_model/validator.rb#L58 for why this is the case.
Related
I'm currently using Spree 3.0 and changed my currency to Colombian Peso (COP). Right now prices are shown like this: ₱80.000,00. I want them to look like this: $ 80.000. I have an idea on how to remove the two 0 after the comma but haven't been able to change the currency symbol for $. This is what I have so far:
in /config/initializers/spree.rb
Spree.config do |config|
config.logo = 'templo samadhi logo.png'
config.admin_interface_logo = 'templo samadhi logo.png'
country = Spree::Country.find_by_name('Colombia')
config.default_country_id = country.id if country.present?
config.checkout_zone = country.id
Money::Currency.register({
:priority => 1,
:iso_code => "COP",
:iso_numeric => country.id,
:name => "Colombia",
:symbol => "$ ",
:subunit => "Cent",
:subunit_to_unit => 100,
:separator => ".",
:delimiter => ","
})
end
This is somehow working because the ₱ symbol is getting removed but the $ is not showing up.
I appreciate if someone can help me with this.
UPDATE
I added the following and now I'm removing the two 0 after the comma but I'm also getting a $ after the price like this: 80.000 $.
So right now I don't know how to move the $ symbol before the price.
Spree::Money.class_eval do
def to_s
formatted = #money.format(#options)
formatted.gsub(/,00/, "")
formatted.symbol_position == :before
end
def to_html(options = { :html => true })
to_s
end
end
I was using this solution but found an issue when I try to process the payment through the stripe gateway, it actually needs the amount subunit to be "Cents" in order to make the currency conversion.
With the #luisjar answer you actually don't use subunits in the COP currency but they may be needed for some payment gateways like stripe. In order to use the COP currency (or any other currency) with a subunit but without showing it, you need to set the format property no_cents true. This is the way I show the amount in Colombian Peso currency like $ 10,000 COP.
Spree.config do |config|
#Change currency symbol for Colombia
country = Spree::Country.find_by_name('Colombia')
config.default_country_id = country.id if country.present?
config.checkout_zone = country.id
Spree::Money.class_eval do
def to_s
#money.format.gsub(/,00/, "")
#money.format(:symbol_position => :before, :with_currency => true, :no_cents => true)
end
def to_html(options = { :html => true })
to_s
end
end
Money::Currency.register({
:priority => 1,
:iso_code => "COP",
:iso_numeric => country.id,
:name => "Colombia",
:symbol => "$ ",
:subunit => "Cent",
:subunit_to_unit => 100,
:separator => ".",
:delimiter => ","
})
Spree::Price.update_all(currency: 'COP')
end
I hope this help to any other confused (like me) with the currencies in Spree.
You can read more about currency format in: https://github.com/RubyMoney/money/blob/master/lib/money/money/formatting.rb
With the code, you merely register another currency. Each product(-variant) has many prices, one per currency. You should make sure, probably in a migration, that all your prices on all your variants are updated to use the correct currency.
Spree::Price.update_all(currency: 'COP')
If you don't want to loose the Dollar prices, but instead want to add an additional price, you need to edit each one manually, or on a migration.
Spree::Price.find_each do |price|
Spree::Price.create(variant: price.variant, amount: price.amount * 1.337, currency: 'COP')
end
Where 1.337 is a conversion factor.
I finally found how to remove the two ceros after the comma, use the $ symbol but still use the Colombian peso Currency. This is the way I did it.
Spree.config do |config|
config.logo = 'templo samadhi logo.png'
config.admin_interface_logo = 'templo samadhi logo.png'
country = Spree::Country.find_by_name('Colombia')
config.default_country_id = country.id if country.present?
config.checkout_zone = country.id
Spree::Money.class_eval do
def to_s
#money.format.gsub(/,00/, "")
#money.format(:symbol_position => :before)
end
def to_html(options = { :html => true })
to_s
end
end
Money::Currency.register({
:priority => 1,
:iso_code => "COP",
:iso_numeric => country.id,
:name => "Colombia",
:symbol => "$ ",
:subunit => "Peso",
:subunit_to_unit => 1,
:separator => ".",
:delimiter => ","
})
end
Looking at documentation of class Currency (in gems/money_6.9.0/lib/money/currency.rb) I found better the following settings:
Money::Currency.register({
:priority => 1,
:iso_code => "COP",
:iso_numeric => country.id,
:name => "Peso",
:symbol => "$",
:html_entity => "$ ",
:symbol_first => true,
:subunit => "Cent",
:subunit_to_unit => 100,
:separator => ".",
:delimiter => ","
})
The "name" attribute is the name of the currency, not the name of the country. The space between the $ and the number goes inside the "html_entity" and not in the symbol. Finally, the "symbol_first" attribute controls where to place the symbol.
I'm building a site for SpreeCommerce 2.1.3, and I'm stuck trying to figure out how to format the prices correctly.
The currency is DKK (Danish Kroner) and I'm looking for the following:
1000 => kr. 1.000,-
1000.50 => kr. 1.000,50
Spree formats my prices like this:
1000 => kr.1.000,00
1000.50 => kr.1.000,50
So there are two problems:
I need a space between kr. and the price.
When there arent any decimals, I would like the decimals rendered as ,- (example: 1.000,-)
How do I accomplish that?
Here's my configuration from config/initializers/spree.rb:
Spree.config do |config|
# [...]
config.currency = "DKK"
config.currency_symbol_position = "before"
config.currency_decimal_mark = ","
config.currency_thousands_separator = "."
end
Solution:
1) I added this decorator to Spree::Money (to replace ,00 with ,-):
Spree::Money.class_eval do
def to_s
formatted = #money.format(#options)
formatted.gsub(/,00$/, ",-")
end
def to_html(options = { :html => true })
to_s
end
end
2) I configured danish currency in my initializer (to add the space after kr.):
Money::Currency.register({
:priority => 1,
:iso_code => "DKK",
:iso_numeric => "208",
:name => "Danish krone",
:symbol => "kr. ",
:subunit => "Øre",
:subunit_to_unit => 100,
:separator => ".",
:delimiter => ","
})
You can customize https://github.com/spree/spree/blob/master/core/lib/spree/money.rb as you want by overriding it.
How would I save this array in one call with Rails?
tax_rates = [{
:income_from => 0
:income_to => 18200
:start => "01-07-2013"
:finish => "30-06-2014"
:rate => nil
:premium => nil
},{
:income_from => 18201
:income_to => 37000
:start => "01-07-2013"
:finish => "30-06-2014"
:rate => 0.19
:premium => nil
},{
:income_from => 18201
:income_to => 37000
:start => "01-07-2013"
:finish => "30-06-2014"
:rate => 0.19
:premium => nil
}]
Can I just call Rails.create(tax_rates)?
Also, is there a way to remove duplicate symbols so they look neater?
Your example is almost correct.
Use ActiveRecord::Persistence#create, which can accept an array of hashes as a parameter.
tax_rates = [
{
income_from: 0,
income_to: 18200,
start: "01-07-2013",
finish: "30-06-2014",
rate: nil,
premium: nil,
},
{
income_from: 18201,
income_to: 37000,
start: "01-07-2013",
finish: "30-06-2014",
rate: 0.19,
premium: nil,
},
# ...
]
TaxRate.create(tax_rates) # Or `create!` to raise if validations fail
A nice solution is to use the active record import gem. I recommend it over now built-in Rails bulk insert because it's more flexible in the options in case of constraint violation.
TaxRate.import(
[:income_from, :income_to, :start, :finish, :rate, :premium],
tax_rates
)
Its definitely better than my old answer which would trigger a db commit per entry in the array :)
Old answer:
tax_rates.map {|tax_rate| TaxRate.new(tax_rate).save }
This way you'll retrieve an Array with true or false to know which did succeed and which didn't.
If you want all of them to be saved .or, non of them to be saved even if one fails, you can use 'ActiveRecord::Base.transaction'
e.g.
ActiveRecord::Base.transaction do
tax_rate.each do |tax_rt|
TaxRate.new(tax_rt).save
end
end
I am not sure about rails < 4.2 but I have tried it in rails 4.2 you can simply do this
TaxRate.create(tax_rt)
Here is an example like yours:
a = []
a << B.new(:name => "c")
a << B.new(:name => "s")
a << B.new(:name => "e")
a << B.new(:name => "t")
The array is saved all at once with:
a.each(&:save)
This will call B#save on each item in the array.
use a gem 'fast_inserter': https://github.com/joinhandshake/fast_inserter
it generates a single sql query of thousand records.
movie_data = [1, 'Climates (Iklimler)', 'Clay Pauwel', 'Drama'],
[2, 'Tinpis Run', 'Andros Glazer', 'Comedy'],
[3, 'Naked City, The', 'Bethena Chatband', 'Mystery'],
[4, 'Small Time Crooks', 'Naomi Plom', 'Crime'],
[5, 'Shadowboxer', 'Georgeanne Widdicombe', 'Thriller']
params = {
table: 'movies',
static_columns: {
created_at: '0000-00-00 00:00:00',
updated_at: '0000-00-00 00:00:00',
},
options: {
timestamps: false,
unique: true,
check_for_existing: true
},
group_size: 100,
variable_columns: %w(id title director description),
values: movie_data
}
inserter = FastInserter::Base.new(params)
inserter.fast_insert
I've got a model User which has id, name, surname, role_id, permission_id
Here is few user entries :
User => {:name => 'Bob', :surname => 'surnmae', :role_id => 1, :permission_id = 2}
User => {:name => 'Alice', :surname => 'strange', :role_id => 1, :permission_id = 3}
User => {:name => 'Ted', :surname => 'Teddy', :role_id => 2, :permission_id = 3}
Now I need to group them first by role_id and then by permission_id, here is what I mean :
Category.select([:name, :role_id, :permission_id]).group_by(&:role_id)
Produces :
{1 =>
[#<User name: "Bob", role_id: 1, permission_id: 2>,
#<User name: "Alice", role_id: 1, permission_id: 3>]
2 => [#<User name: "Ted", role_id: 2, permission_id: 3>]
}
Which is close enough but I need them grouped with permission_id as well so it would look like this :
{:role_id => {:permision_id => [Array of users grouped by this criteria]}
}
It is bit more tricky than it seems. It is better to write it into multiple steps. However, the following one-liner will work:
Hash[ User.all.group_by(&:role_id).collect{|role, grp| [role, grp.group_by(&:permission_id)]} ]
Output will be the following (which is probably what you are looking for):
{1=>
{2=>[{:name=>"Bob", :surname=>"surnmae", :role_id=>1, :permission_id=>2}],
3=>[{:name=>"Alice", :surname=>"strange", :role_id=>1, :permission_id=>3}]},
2=>{3=>[{:name=>"Ted", :surname=>"Teddy", :role_id=>2, :permission_id=>3}]}}
Same logic, but simpler to comprehend:
output={}
User.all.group_by(&:role_id).each{|role, grp| output[role]= grp.group_by(&:permission_id)}
# output has required goruping
maybe something like
Category.select([:name, :role_id, :permission_id]).group_by(&:role_id).map{|role| role.group_by(&:permission_id)}
Category.select([:name, :role_id, :permission_id]).group_by { |category| [category.role_id, category.permission_id] }
Edit: Nevermind, this doesn't provide quite the formatting you're looking for.
I am in a rails 3.2.6 app using the gems money and money-rails.
For money-rails I have set-up an initializer with this data:
MoneyRails.configure do |config|
config.default_currency = :eur
config.register_currency = {
:id => :euc,
:priority => 1,
:iso_code => "EUR",
:name => "Euro with Comma decimal mark",
:symbol => "€",
:symbol_first => true,
:subunit => "Cent",
:subunit_to_unit => 100,
:thousands_separator => ".",
:decimal_mark => ","
}
end
Note I have created a new currency :euc, because I want to display the euro currency with the comma decimal separator,
but the problem is the money object doesn't display yet the comma, for example:
amount = Money.new(100, 'EUR')
amount.to_s
or in a view:
<%= humanized_money amount %>
it display "1.00 instead of "1,00"
where am I doing wrong?
Try using amount.format(decimal_mark: ",") for now. It seems like a bug.
Try
100.to_money('EUR')
Money.new(100) considers 100 to be in cents.