ruby 1.9.3 round decimals - ruby-on-rails

I'm using round(2) to round the decimals but for some reason when I do that in my controller, randomly it convert it. If I try this in rails console then it converts it to 651.44
Here is what I'm using in my rails migration
t.decimal :balance, :precision => 8, :scale => 2, :null => false

Related

Ruby on Rails decimal comparison stopped working

I have been using a state object in the database that keeps track of what seed data has been loaded into it. The structure of the table is:
create_table "toolkit_states", force: :cascade do |t|
t.boolean "signups", default: true
t.decimal "database_version", precision: 5, scale: 2
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
The seeds.rb file checks the database_version and runs blocks of code and then sets the database_version after running the block. It has worked fine from versions 0.1 up to 0.55.
I added a new block of seed data. To run that block the database_version is checked and it should be 0.56. The following comparison does not work:
if state.database_version == 0.56
For some reason, the number 0.56 cannot be evaluated for equality with the value stored in the database. It has worked on all the values up to 0.56.
Here is a rails console session:
irb(main):001:0> state = ToolkitState.first
ToolkitState Load (0.4ms) SELECT "toolkit_states".* FROM "toolkit_states" ORDER BY "toolkit_states"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<ToolkitState id: 1, signups: false, database_version: 0.56e0, created_at: "2018-12-27 17:04:50", updated_at: "2018-12-27 17:04:56">
irb(main):002:0> state.database_version == 0.56
=> false
irb(main):003:0> state.database_version == 0.56e0
=> false
irb(main):004:0> state.database_version == 0.56.to_f
=> false
irb(main):005:0> state.database_version.to_f == 0.56
=> true
When I convert the value with a "to_f", the comparison works. My problem is that it as worked well without this conversion up to the value, 0.56
It occurs because state.database_version is an instance of BigDecimal class. This article explain why it is BigDecimal.
Look at this example:
BigDecimal('0.56e0')
=> 0.56e0
irb(main):008:0> BigDecimal('0.56e0') == 0.56
=> false
irb(main):009:0> BigDecimal('0.56e0').to_f
=> 0.56
As you can see 0.56e0 after transformation to float type becomes 0.56 and your comparison returns true.
Nate explained more briefly why it's happening in this comment.
irb(main):001:0> c = BigDecimal('0.56e0')
=> 0.56e0
irb(main):002:0> c == 0.56
=> false
irb(main):003:0> c = BigDecimal('0.55e0')
=> 0.55e0
irb(main):004:0> c == 0.55
=> true
Works for 0.55 and not for 0.56 Rails bug?

Searching UNIX timestamp gives differing results

The following queries give different results, the result for both should be two. I'm using timestamp columns in my db (postgres), and am searching for objects where their end_at column is less than or equal to a given UNIX timestamp.
puts object.time_records.where('time_records.end_at <= ?', object.time_records.second.end_at).count #=> 2 (Correct)
puts object.time_records.where('time_records.end_at <= ?', DateTime.strptime(object.time_records.second.end_at.to_i.to_s, '%s')).count # => 1 (Incorrect)
puts object.time_records.where('time_records.end_at <= ?', Time.at(object.time_records.second.end_at.to_i)).count # => 1 (Incorrect)
If I seed some data, the timestamp used in the query might be, for example:
1473024092
Then if I print the timestamps for the object:
puts object.time_records.pluck(:end_at).map(&:to_i)
I get the following results:
1472419292
1473024092
1473628892
1474233692
As can be seen from these, the correct result should be two. If anyone has encountered something similar I'd appreciate a pointer in the right direction.
For what it's worth, this is occurring in specs I'm writing for a gem. I've tried varying combinations of in_time_zone and .utc for parsing and converting to the timestamp, and they all offer the same result. Even converting to a timestamp and straight back to a Time, and testing for equality results in false, when to_s is equal for both.
I ran an example in irb:
2.3.0 :001 > now = Time.now
=> 2016-08-28 21:58:43 +0100
2.3.0 :002 > timestamp = now.to_i
=> 1472417923
2.3.0 :003 > parsed_timestamp = Time.at(timestamp)
=> 2016-08-28 21:58:43 +0100
2.3.0 :004 > now.eql?(parsed_timestamp)
=> false
2.3.0 :005 > now == parsed_timestamp
=> false
2.3.0 :006 > now === parsed_timestamp
=> false
2.3.0 :007 > now.class
=> Time
2.3.0 :008 > parsed_timestamp.class
=> Time
The issue was fractional times. UNIX timestamps are to the second, so when converting to_i, the milliseconds are discarded.
Setting the precision of the timestamp columns resolved this issue:
class CreateTimeRecords < ActiveRecord::Migration
def change
create_table :time_records do |t|
t.belongs_to :object, index: true, null: false
t.datetime :start_at, null: false, index: true, precision: 0
t.datetime :end_at, null: false, index: true, precision: 0
t.timestamps null: false
end
end
end

"PG::Error - numeric field overflow" on Heroku

I have built an app that queries Google Analytics for the last 7 days of data. Everything works locally. On Heroku, the process runs smoothly until it tries to get data for today's date. I then get the following error:
2012-10-29T02:32:02+00:00 app[web.1]: ActiveRecord::StatementInvalid (PG::Error: ERROR: numeric field overflow
2012-10-29T02:32:02+00:00 app[web.1]: DETAIL: A field with precision 8, scale 2 must round to an absolute value less than 10^6.
I have tried to figure out which variable it's not happy with but I don't know right now. I am assuming it's something related to date or time.
Any thoughts or ideas would be great :)
-- update ---
ActiveRecord::Schema.define(:version => 20121014153338) do
create_table "analytics", :force => true do |t|
t.string "site"
t.integer "visits"
t.date "start_date"
t.date "end_date"
t.decimal "revenue_per_transaction", :precision => 8, :scale => 2
t.integer "transactions"
t.decimal "item_quantity", :precision => 8, :scale => 2
t.integer "goal_starts"
t.integer "goal_completes"
t.decimal "goal_conversion", :precision => 8, :scale => 2
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.decimal "goal_abandon", :precision => 8, :scale => 2
t.decimal "revenue", :precision => 8, :scale => 2
t.string "source"
end
end
You have a numeric field with typmod numeric(8,2) and you're trying to store a value greater than 999999.99 in it. See the PostgreSQL manual on NUMERIC for information on numeric scale and precision, which are the qualifiers shown after the type in parentheses.
This earlier question appears to cover the same issue with Rails, showing the Rails model and how the scale and precision are assigned.
NUMERIC isn't a date/time field, it's a number field.
Demo of the issue:
regress=> SELECT NUMERIC(8,2) '999999.99';
numeric
-----------
999999.99
(1 row)
regress=> SELECT NUMERIC(8,2) '1000000.00';
ERROR: numeric field overflow
DETAIL: A field with precision 8, scale 2 must round to an absolute value less than 10^6.
It's a pity that Pg doesn't tell you what field this is when it is a field. It's difficult for it to do so, though, because it doesn't usually know which value is going to go into which field when it's parsing string literals. Enable log_statement = 'all' in postgresql.conf, ALTER USER ... SET, ALTER DATABASE ... SET, or per-session with SET log_statement = 'all' then re-test and examine the query logs.
Also look at the table definitions with \dt in psql to see what might have the type numeric(8,2) and could be causing the problem.
As for why it works locally: Is the local DB PostgreSQL? Some Rails users seem to have a very odd setup where they use SQLite locally, and PostgreSQL on Heroku. This is a recipe for chaos and deployment problems. Use the same database in development and testing. If it is PostgreSQL locally, is it the same version?

Unset operation failing for MongoMapper model, cannot delete / remove key from model

We're on mongodb 2.0.0, mongo gem 1.4.1, mongo_mapper 0.9.2, rails 3.0.6.
We love MongoMapper, but we need helping resolving one nasty issue: we have a key carried over from some testing, but invoking obj.unset fails to do anything.
Specifically, we are trying to remove an "id" key (not "_id") because it's causing MM to treat obj.id as different from obj._id, which we don't want.
After clearing out the database, we ran these commands from a controller which does nothing else: (We also tried running the same code from the rails console, but it also fails.)
logger.info "#{Game.keys.keys.inspect}"
Game.unset({}, :id)
logger.info "#{Game.keys.keys.inspect}"
Game.unset(:id)
logger.info "#{Game.keys.keys.inspect}"
Output:
["jackpot", "players", "created_at", "puzzles", "ended_at", "player_index", "updated_at", "log", "_id", "id", "join_code", "puzzle_index"]
["jackpot", "players", "created_at", "puzzles", "ended_at", "player_index", "updated_at", "log", "_id", "id", "join_code", "puzzle_index"]
["jackpot", "players", "created_at", "puzzles", "ended_at", "player_index", "updated_at", "log", "_id", "id", "join_code", "puzzle_index"]
Current keys defined in our Game model:
key :players, Array, :default => []
key :player_index, Integer, :default => 0
key :puzzles, Array, :default => []
key :puzzle_index, Integer, :default => 0
key :join_code, String, :default => nil
key :jackpot, Integer, :default => 0
key :log, Array, :default => []
key :created_at, Time
key :updated_at, Time
key :ended_at, Time, :default => nil
Help?
Thanks!
It pains us to post the answer since this solidifies our status as "morons, idiots, fools, noobs, Jay Leno fans," but in case anyone else bumps into the same issue: while our model directory was clean in the dev environment, the model dir in the production environment contained old test files ... which contained an old model with the "id" key.
Obviously, removing the old files and the old models solved everything, though we're left with staggering bruises to our egos and to our heads (from excessive banging against the walls).

RAILS precision and scale of decimal is not working

I have set :precision => 8, :scale => 2 in decimal of migration but when i input 1923.423453 it is still 1923.4 . It should be 1923.42 ... right?
t.decimal :value , :precision => 8, :scale => 2 , :default => 0
Apparently all sqlite options are dropped on migration.
Here's the lighthouse ticket targeting milestone 3.0.4 to fix this issue:
https://rails.lighthouseapp.com/projects/8994/tickets/2872-patch-sqlite3-adapter-drops-decimal-columns-precision-scale-when-migration-tries-to-alter-them

Resources