Entering in large dollar values into rails money object - ruby-on-rails

I have built an application running rails 4.1 and ruby 1.9.3 that uses the money-rails gem. I'm encountering an issue when I input large dollar values into form fields and save them to my PG database. The error is the following:
PG::NumericValueOutOfRange: ERROR: value "9900000000" is out of range for type integer
The PG docs show the max value of an integer being +2147483647. I would like to be able to use the money-rails gem but be able to enter larger numbers.
As far as a solution goes, I understand that the column type in PG should be a bigint, however I'm not how to enable money-rails to support storing numbers as bigint instead of integers.

Here in the money-rails README it shows that you can configure it to use other data types:
# Default ActiveRecord migration configuration values for columns:
#
# config.amount_column = { prefix: '', # column name prefix
# postfix: '_cents', # column name postfix
# column_name: nil, # full column name (overrides prefix, postfix and accessor name)
# type: :integer, # column type
# present: true, # column will be created
# null: false, # other options will be treated as column options
# default: 0
# }
Notice there's a type: :integer option. Try changing that to :bigint.

I had similar question recently (with ruby 2.0 & rails 4.1). The only thing that was required is creating migration to support 8-byte integers, i.e. bigint:
change_column :order_items, :unit_price_cents, :integer, :limit => 8
And it just worked. I my case I needed to support also 4 decimals, so I had to recreate USD currency as follows:
MoneyRails.configure do |config|
config.register_currency = {
:priority => 1,
:iso_code => "USD",
:iso_numeric => "840",
:name => "United States Dollar with subunit of 4 digits",
:symbol => "$",
:symbol_first => true,
:subunit => "Subcent",
:subunit_to_unit => 10000,
:separator => ".",
:delimiter => ","
}
end

Related

RAILS: undefined method `map' caused by missing I18n translation

I changed the format for a datetime field in a RAILS 4 new.html.erb from :string to datetime and it caused error as below:
undefined method `map' for "translation missing: zh-CN.date.order":String
The view code causing the error above is:
<%= f.input :start_time, :label => t("Start Time"), required: true, :as => :datetime, :ampm => true, :minute_step => 10, :start_year => Date.today.year - 1, :end_year => Date.today.year + 1, :format => 'YYYY/MM/DD/HH/MM', :use_month_numbers => true, :include_blank => true %>
The RAILS source code blows up is in actionview/helpers/date_helper.rb:
def translated_date_order
date_order = I18n.translate(:'date.order', :locale => #options[:locale], :default => [])
date_order = date_order.map { |element| element.to_sym } #<<<<<<===blows up
forbidden_elements = date_order - [:year, :month, :day]
if forbidden_elements.any?
raise StandardError,
"#{#options[:locale]}.date.order only accepts :year, :month and :day"
end
date_order
end
I do have a file zh-CN.yml under /config/locale/ and it is providing translations for others except this one.
UPDATE portion of zh-CN.yml:
zh-CN:
#maint_recordx
Mfg Batches : '订单批次一览'
New Batch : '新批次'
Update Batch : '更新批次'
Edit Batch : '更新批次'
...........
After being bitten by this same error, I found that Rails sets the following key:
:'date.order'
to the value:
["year", "month", "day"]
for the default :en locale
You can confirm this by running the following snippet in rails console for a default rails install:
date_order = I18n.translate(:'date.order', :locale => :en, :default => [])
Notice I just switched #options[:locale] for the default :en value
The rails helper you reference, expects an array for the date_order value, and will blow up if it doesn't get one.
In my case, I improperly configured the I18n::Backend::ActiveRecord gem and therefore it interfered with the value being returned by I18n. You probably have a similar issue preventing the correct value for the :'date.order' key being returned.
EDIT:
In order to fix this, you should probably just need to install the gem 'rails-i18n'. It will handle returning the correct date formats for supported locales. In my case I had a custom configuration in my es.yml locale file that returned an incorrect date format.
Bingo !!! You just have to add the missing key translation to your local translations.
I solved it by adding
en:
date:
order: ["day", "month", "year"]
to
config/locales/en.yml

Spree/Solidus: format currency to show symbol before price with space "€ 99"

I use Rails 4 and Solidus 1.2
How does one format the price to have a currency symbol with a space before the number like "€ 99"?
Spree/Solidus use Ruby Money Gem to handle currencies and I see in https://github.com/RubyMoney/money/blob/master/lib/money/money/formatting.rb that there is a config option
Spree::Money.default_formatting_rules[:symbol_before_without_space] = true
but no Spree::Money.default_formatting_rules[:symbol_before_with_space] = true
In my initializer:
# config/initializers/spree.rb
Money::Currency.register({
:priority => 1,
:iso_code => "EUR",
:iso_numeric => "978",
:name => "Euro",
:symbol => "€",
:subunit => "Cent",
:subunit_to_unit => 100,
:separator => ".",
:delimiter => ","
})
And I tried also to format within my localization files like in de.yml:
---
de:
number:
currency:
format: "%u %n"
But the price format is still "104,90 €" instead of "€ 104,90".
I don't want to do String Interpolation to format the currency. Is there an config option that I'm missing?
ok, it's embarrassing but i just had to set
Spree::Money.default_formatting_rules[:symbol_before_without_space] = false
to get my desired format.
You will need to do
Spree::Money.default_formatting_rules[:symbol_position] = :before

Changing the currency format for product prices within Spree

I'm upgrading spree to from spree 1.0 to 1.3 and get stuck with the new currency options.
I want to render prices as: '€ 100' but instead get '€100'. How do I get a space between the unit and the value?
Note: Changing the locale file doesn't work, since it uses the money gem.
There are a bunch of ways to do this. The easiest would probably be to re-register the Euro currency with a different symbol.
Put the following in an initializer:
# encoding: utf-8
Money::Currency.register({
:priority => 1,
:iso_code => "EUR",
:iso_numeric => "978",
:name => "Euro",
:symbol => "€ ",
:subunit => "Cent",
:subunit_to_unit => 100,
:separator => ".",
:delimiter => ","
})
A rails console now reports:
> Spree::Money.new(100, currency: 'EUR')
=> € 100.00
I did the following in my config/initializers/spree.rb to inject a different symbol:
Money::Currency.table[:chf].merge!(symbol: 'CHF ')
This way the currencies aren't going to mix up.
Thanks a lot.
In my case, used the following to change the symbol generated by the to_html method, in case anyone has the same problem.
# encoding: utf-8
Money::Currency.register({
:priority => 1,
:iso_code => "CLP",
:iso_numeric => "152",
:name => "Chilean Peso",
:symbol => "$",
:subunit => "Peso",
:subunit_to_unit => 1,
:separator => ",",
:delimiter => ".",
html_entity: "$"
})
I solved the problem with the following in an initializer, e.g. config/initializers/currency_formatting.rb:
# Display prices with a space between symbol and number:
Spree::Money.default_formatting_rules[:symbol_before_without_space] = false
This hooks into the formatting rules found in Spree::Money, which can control all the formatting Options of the Money Gem, including the one placing a space between the symbol and the number. This has the advantage over the other solutions presented here that it works with all currencies at once.
Okay, this was pretty easy. As of gem version money(6.16.0).
In Spree intializer spree.rb Recommended way:
Spree.config do |config|
...
...
# Below is deprecated
Spree::Money.default_formatting_rules[:symbol_before_without_space] = false
# Instead try this
Spree::Money.default_formatting_rules[:format] = '%u %n'
end

Ruby add_item for eBay

I am attempting to write a ruby on rails app that posts an item to eBay. Cody Fauser/Garry Tan have a gem called ebayApi which is built on top of the ebay gem. When I attempt to post an item, I am getting an error back from ebay that says the condition ID is required for this category. I have found a category that does not require the condition, and I can post to that category. Searching through the eBay API documentation, I have found a tag conditionID under the "item" class. However, in the documentation for ebayAPI, there is no such tag. Looking back at the ebay API documentation, there is an older way to specify condition, using lookup_attributes. I have noted that the return xml is coming in API version 745, and Garry Gan's updated of the ruby interface is running version 609. I have tried using the lookup, and seem to get the same error (condition required). I am using the following code to specify the item:
#ebay = Ebay::Api.new :auth_token => #seller.ebay_token
item = Ebay::Types::Item.new( :primary_category => Ebay::Types::Category.new(:category_id => #ebayTemplate.categoryID),
:title => #ebayTemplate.name,
:description => #ebayTemplate.description,
:location => #ebayTemplate.location,
:start_price => Money.new((#ebayTemplate.startPrice*100).to_d, #ebayTemplate.currency),
:quantity => 1,
:listing_duration => #ebayTemplate.listingDuration,
:country => #ebayTemplate.country,
:currency => #ebayTemplate.currency,
:payment_methods => ['VisaMC', 'PayPal'],
:paypal_email_address => '********#gmail.com',
:dispatch_time_max => 3,
:lookup_attributes => [Ebay::Types::LookupAttribute.new( :name => "Condition", :value => "New")],
# :attribute_sets => [
# Ebay::Types::AttributeSet.new(
# :attribute_set_id => 2919,
# :attributes => [
# Ebay::Types::Attribute.new(
# :attribute_id => 10244,
# :values => [ Ebay::Types::Val.new(:value_id => 10425) ]
# )
# ]
# )
# ],
:shipping_details => Ebay::Types::ShippingDetails.new(
:shipping_service_options => [
# ShippingServiceOptions.new(
# :shipping_service_priority => 2, # Display priority in the listing
# :shipping_service => 'UPSNextDay',
# :shipping_service_cost => Money.new(1000, 'USD'),
# :shipping_surcharge => Money.new(299, 'USD')
# ),
Ebay::Types::ShippingServiceOptions.new(
:shipping_service_priority => 1, # Display priority in the listing
:shipping_service => #ebayTemplate.shipSvc,
:shipping_service_cost => Money.new((#ebayTemplate.shipSvcCost*100).to_d, #ebayTemplate.currency),
:shipping_surcharge => Money.new((#ebayTemplate.shipSurcharge*100).to_d, #ebayTemplate.currency)
)
],
:international_shipping_service_options => [
Ebay::Types::InternationalShippingServiceOptions.new(
:shipping_service => 'USPSPriorityMailInternational',
:shipping_service_cost => Money.new((#ebayTemplate.shipSvcCost*100).to_d, #ebayTemplate.currency),
:shipping_service_priority => 2,
:ship_to_location => #ebayTemplate.shipToLocation
)
]
),
:return_policy => Ebay::Types::ReturnPolicy.new (
:description => 'this product for suckers only!',
:returns_accepted_option => 'ReturnsAccepted'
)
#:condition_id => 1000
)
#response = #ebay.add_item(:item => item)
As you can see, it is just a mutation of the example given by Cody Fauser. The condition_id at the bottom will bring up an error as there is no such attribute. It seems to me there is no facility for this in the gem since the requirement came into existence after the gem was created. I have not been able to find any other gems to connect with ebay. I have also noticed, there are very little complaints about this even though people are still downloading the gem (10 people downloaded it today). I think there are quite a number of people writing for ebay. Is there a key word I am missing to specify the condition? A work around that people have been using? Another gem I have missed?
There is an existing item_conditions_codes.rb in the gem's type directory and only has two values New and Used. Guess you could add more values in there. However still needs mapping to ID's per the updating (and changed from Attributes) method
You have to modify in the gem library in .. ruby/1.8/gems/ebayapi-0.12.0/lib/ebay/types/item.rb
and add the following new lines
# added to allow ConditionID to be pushed into XML
numeric_node :condition_id, 'ConditionID', :optional => true
then in your ruby ebay code use the following convention
:condition_id => 1500,
At least that seems to work for me right now.

Get In That DB! Parsing CSV Using Ruby

I have a CSV file formatted just like this:
name,color,tasty,qty
apple,red,true,3
orange,orange,false,4
pear,greenish-yellowish,true,1
As you can see, each column in the Ruby OO world represents a mix of types -- string, string, boolean, int.
Now, ultimately, I want to parse each line in the file, determine the appropriate type, and insert that row into a database via a Rails migration. For ex:
Fruit.create(:name => 'apple', :color => 'red', :tasty => true, :qty => 3)
Help!
For Ruby 1.8:
require 'fastercsv'
FasterCSV.parse(my_string, :headers => true) do |row|
Fruit.create!(
:name => row['name'],
:color => row['color'],
:tasty => row['tasty'] == 'true',
:qty => row['qty].to_i
)
end
For Ruby 1.9, just rename FasterCSV to CSV and fastercsv to csv:
require 'csv'
CSV.parse(my_string, :headers => true) do |row|
# same as ruby-1.8
end

Resources