RAILS precision and scale of decimal is not working - ruby-on-rails

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

Related

"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?

ruby 1.9.3 round decimals

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

Why does RSpec fail on that validation?

I have these validations :
it "should have 100 adventure points" do
user = User.new
user.adventure_points.should == 100
end
it "should be level 1" do
user = User.new
user.level.should == 1
end
it "should have 10 sapphires" do
user = User.new
user.sapphires.should == 10
end
Then, i also have in my migration :
t.string :name, :limit => 20
t.integer :strength_points, :default => 0
t.integer :dexterity_points, :default => 0
t.integer :magic_points, :default => 0
t.integer :accuracy_points, :default => 0
t.integer :health_points, :default => 0
t.integer :level, :default => 1
t.integer :adventure_points, :default => 100
t.integer :sapphires, :default => 10
t.integer :duel_wins, :default => 0
t.integer :duel_losses, :default => 0
t.string :image_url
t.integer :strength
When i run rspec i get :
A new User
is not valid without a name
is not valid without a first class
is not valid without a password
should have 100 adventure points
should be level 1 (FAILED - 1)
should have 10 sapphires (FAILED - 2)
Failures:
1) A new User should be level 1
Failure/Error: user.level.should == 1
expected: 1
got: nil (using ==)
# ./spec/models/user_spec.rb:28
2) A new User should have 10 sapphires
Failure/Error: user.sapphires.should == 10
expected: 10
got: nil (using ==)
# ./spec/models/user_spec.rb:33
Why does it present these errors on level, sapphires, but it works ok for adventure_points ? Moreover, if i open a console and do User.new, i get the default values as expected. What is hapening here ?
The database defaults are not set until the model is saved. Try:
it "should have 100 adventure points" do
user = User.create
user.adventure_points.should == 100
end
Found the solution myself, pretty sneaky one. I had to run rake:test:prepare because the test database did not have fixtures data and was not prepared :P

prawnto displaying tables that don't break when new page

I have a variable number of tables with variable number of rows and I want to have them displaying one after the other but if a table doesn't fit on the current page put it on the next then continue on. I have put the table in a transaction so I can roll back then print it if the height will fit on curent page but how do I get the table height?
I have this code at the moment
pdf.transaction do
pdf.table #data,
:font_size => 12,
:border_style => :grid,
:horizontal_padding => 10,
:vertical_padding => 3,
:border_width => 2,
:position => :left,
:row_colors => ["FFFFFF","DDDDDD"]
pdf.move_down 20
#pdf.rollback
end
Any help on this would be great. Or any other way to do this ?
Best Regards
Rick
4 years later... :)
As #m-x wrote it, rollback was disabled for security reason, like "group", and is still not implemented. So, here how I deal with break pages for tables :
Big and simple table (one row per data)
Just use header option
pdf.table #data,
header: true, # You can use 'header: 2' if your header take two rows
font_size: 12,
border_style: :grid,
horizontal_padding: 10,
vertical_padding: 3,
border_width: 2,
position: :left,
row_colors: ["FFFFFF","DDDDDD"]
Small table or complexe table
make table
check if you need break page
draw table
With your example :
t = pdf.make_table #data,
font_size: 12,
border_style: :grid,
horizontal_padding: 10,
vertical_padding: 3,
border_width: 2,
position: :left,
row_colors: ["FFFFFF","DDDDDD"]
if cursor - t.height < 0
start_new_page
end
t.draw
Hope that helps
#current_page = pdf.page_count
#roll = pdf.transaction do
pdf.move_down 20
pdf.table #data,
:font_size => 12,
:border_style => :grid,
:horizontal_padding => 10,
:vertical_padding => 3,
:border_width => 2,
:position => :left,
:row_colors => ["FFFFFF","DDDDDD"]
pdf.rollback if pdf.page_count > #current_page
end
if #roll == false
pdf.start_new_page
pdf.table #data,
:font_size => 12,
:border_style => :grid,
:horizontal_padding => 10,
:vertical_padding => 3,
:border_width => 2,
:position => :left,
:row_colors => ["FFFFFF","DDDDDD"]
end
I hope this works for you as for me :-)
I'm a Prawn beginner, so this might not be the best solution, but it should work.
You can get the table height if you consider the font size and vertical padding and the number of records you have in #data and you can get the current cursor position by calling Prawn::Document.cursor method.
Having these two numbers you should be able to check whether the table fits on this page or not. If not, just start a new one (by calling Prawn::Document.start_new_page method).
Otherwise the table will break automatically and will continue on the next page.
Thanks Igor
I am currently setting the current page and then in the transaction after the new table has been rendered and before the roll back setting new_page variable. Then i can roll back and chek if the new page var > current page var and if it is start new page and print the table. See code below.
The problem is now the pdf.start_new_page says error but if i just take the pdf.rollback line out it works. See error below.
Any ideas any one or any easier ways, there must be one!!
thanks
rick
#current_page = pdf.page_count
pdf.transaction do
pdf.move_down 20
pdf.table #data,
:font_size => 12,
:border_style => :grid,
:horizontal_padding => 10,
:vertical_padding => 3,
:border_width => 2,
:position => :left,
:row_colors => ["FFFFFF","DDDDDD"]
#the_next_page = pdf.page_count
pdf.rollback
end
if #the_next_page > #current_page
pdf.start_new_page
pdf.table #data,
:font_size => 12,
:border_style => :grid,
:horizontal_padding => 10,
:vertical_padding => 3,
:border_width => 2,
:position => :left,
:row_colors => ["FFFFFF","DDDDDD"]
end
The error
> You have a nil object when you didn't expect it!
The error occurred while evaluating nil.identifier
Extracted source (around line #158):
155: end
RAILS_ROOT: C:/InstantRails/rails_apps/Macrotec-Application
Application Trace | Framework Trace | Full Trace
c:/InstantRails/ruby/lib/ruby/gems/1.8/gems/prawn-core-0.7.1/lib/prawn/document.rb:302:in `go_to_page'
c:/InstantRails/ruby/lib/ruby/gems/1.8/gems/prawn-core-0.7.1/lib/prawn/document/internals.rb:128:in `finalize_all_page_contents'
c:/InstantRails/ruby/lib/ruby/gems/1.8/gems/prawn-core-0.7.1/lib/prawn/document/internals.rb:127:in `each'
c:/InstantRails/ruby/lib/ruby/gems/1.8/gems/prawn-core-0.7.1/lib/prawn/document/internals.rb:127:in `finalize_all_page_contents'
c:/InstantRails/ruby/lib/ruby/gems/1.8/gems/prawn-core-0.7.1/lib/prawn/document.rb:344:in `render'
C:/InstantRails/rails_apps/Macrotec-Application/app/views/quotations/show.pdf.prawn:158:in `_run_prawn_app47views47quotations47show46pdf46prawn'

Friendly Byte Formatting in Rails

I need to format an integer representation of bytes into something friendly, and I'm hoping that there's a utility function in Ruby or in Rails that will do that formatting for me (to perpetuate my laziness, of course.)
I'm looking for something that would look like:
format_bytes(1024) -> "1 KB"
format_bytes(1048576) -> "1 MB"
Looks like there's some stuff in ActiveSupport to do it the other way around, but I haven't found a way to do it in this direction.
If there isn't one that exists, does anyone have a particularly elegant solution?
Number to human size is what you're looking for.
require 'action_view'
include ActionView::Helpers::NumberHelper
number_to_human_size(123) # => 123 Bytes
number_to_human_size(1234) # => 1.2 KB
number_to_human_size(12345) # => 12.1 KB
number_to_human_size(1234567) # => 1.2 MB
number_to_human_size(1234567890) # => 1.1 GB
number_to_human_size(1234567890123) # => 1.1 TB
number_to_human_size(1234567, :precision => 2) # => 1.18 MB
number_to_human_size(483989, :precision => 0) # => 473 KB
number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
Accepted answer still work, but requires actionpack instead of actionview in newer rails.
require 'actionpack'
Accepted answer it's perfect, but I didn't need the first two lines.
I only put:
number_to_human_size(123) # => 123 Bytes
number_to_human_size(1234) # => 1.2 KB
number_to_human_size(12345) # => 12.1 KB
number_to_human_size(1234567) # => 1.2 MB
number_to_human_size(1234567890) # => 1.1 GB
number_to_human_size(1234567890123) # => 1.1 TB
number_to_human_size(1234567, :precision => 2) # => 1.18 MB
number_to_human_size(483989, :precision => 0) # => 473 KB
number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
and works like a charm.

Resources