Rails 3 Float Rounding Error - ruby-on-rails-3

Running ruby 1.8.7.
(1.005 * 100).round
result: 100
(1.006 * 100).round
result: 101
100.5.round
result: 101
(1.005 * 100)
result: 100.5
What is going on here? Can someone try this in the latest version of ruby please?
Thanks!

Floating Point Math is what's going on.
For the last one, I do not get 100.5, and you aren't either, even if for some reason it's displaying as that:
Loading development environment (Rails 3.2.8)
1.9.3p194 :001 > (1.005 * 100).round
=> 100
1.9.3p194 :002 > (1.006 * 100).round
=> 101
1.9.3p194 :003 > 100.5.round
=> 101
1.9.3p194 :004 > (1.005 * 100)
=> 100.49999999999999

Related

Select model based on amount of related models with certain conditions

I have a Post that has_many :comments. Let's say Comment has the following field: another_model_id. I would like to select Posts, that have from 2 to 5 comments with another_model_id = 10 (for example). I tried several constructions but with no success :(
Example of what I tried:
# Invalid SQL syntax error
Post
.joins(:comments)
.select("count(comment.another_model_id = 10) as comments_count)
.where("comments_count BETWEEN 2 AND 5")
I have literally no idea where to dig. Is it possible to achieve that in a single query? Thanks!
Post
.joins(:comments)
.where(comments: { another_model_id: 10 })
.group('posts.id')
.having('count(comments.id) > 2 AND count(comments.id) < 5')
Using counter_cache is the best practice for your scenario:
In your Comment model, you need to set the counter_cache:
belongs_to :post, counter_cache: true
Then simply you can use this query:
Post.joins(:comments)
.where(comments: { another_model_id: 10 })
.where('comments_count > ? AND comments_count < ?', 2, 5)

Rails changing query execution order

I want to perform a query on first 10 records.
So, from Rails console I type:
Log.all.limit(10).where({"username"=>"peeyush"}).explain
This gives:
Log Load (0.8ms) SELECT "logs".* FROM "logs" WHERE "logs"."username" = 'peeyush' LIMIT 10
Clearly, LIMIT 10 happens later.
I try running:
Log.all.first(10).where({"username"=>"peeyush"}).explain
But this gives an error:
NoMethodError: undefined method `where' for #<Array:0x0000000539acd8>
How should the query be performed?
If I understand you correctly, you want to retrieve the 1st 10 rows and then filter those 10 records by username?
Filter in ruby
all.first(10).find_all {|i| i.username == "peeyush" }
Filter on the database
all.where(:id => all.first(10).map {|x| x.id}, :username => "peeyush")

Thinking Sphinx without records within date range error

im trying to find records that are NOT created in a certain date range using a thinking sphinx query in my rails 4 project with postgresql as database
THIS WORKS
Housing.search "some text",
star: true,
ranker: :bm25,
with: {created_at (3.weeks.ago..Time.zone.now)}
BUT THIS DOESN´T
Housing.search "some text",
star: true,
ranker: :bm25,
without: {created_at:(3.weeks.ago..Time.zone.now)}
I´m thinking its a bug in the query since it finds all record within the given date range, but fails to find the opposite?
This is my gemfile
gem 'mysql2', '0.3.12b4'
gem 'thinking-sphinx', github: 'pat/thinking-sphinx'
gem 'flying-sphinx', github: 'flying-sphinx/flying-sphinx'
gem 'delayed_job_active_record', '>= 4.0.0.beta2'
gem 'delayed_job_web'
gem 'ts-delayed-delta', github: 'pat/ts-delayed-delta'
This is my housing_indices
ThinkingSphinx::Index.define :housing, :with => :active_record, :delta => ThinkingSphinx::Deltas::DelayedDelta do
has created_at
< + OTHER FIELDS THAT ARE INDEXED >
set_property :enable_star => true
set_property :min_infix_len => 1
set_property :html_strip => true
set_property :charset_type => "utf-8"
end
this is the query from the log when using without: {created_at:(3.weeks.ago..Time.zone.now)}
Sphinx Query (1.0ms) SELECT * FROM `housing_core`, `housing_delta` WHERE MATCH('#location_name *Krimml*') AND max_capacity BETWEEN 1 AND 1000 AND number_of_bathrooms BETWEEN 1 AND 3 AND number_of_bed_places BETWEEN 2 AND 10 AND sphinx_deleted = 0 AND created_at < 1376554070 OR created_at > 1378368470 AND activated_at <> 0 LIMIT 0, 20 OPTION ranker=bm25
And this Is the error I am getting
sphinxql: syntax error, unexpected OR, expecting $end near 'OR created_at > 1378368470 AND activated_at <> 0 LIMIT 0, 20 OPTION ranker=bm25; SHOW META'
this is the query from the log when using with: {created_at:(3.weeks.ago..Time.zone.now)}
Sphinx Query (3.9ms) SELECT * FROM `housing_core`, `housing_delta` WHERE MATCH('#location_name *Krimml*') AND created_at BETWEEN 1376555152 AND 1378369552 AND max_capacity BETWEEN 1 AND 1000 AND number_of_bathrooms BETWEEN 1 AND 3 AND number_of_bed_places BETWEEN 2 AND 10 AND sphinx_deleted = 0 AND activated_at <> 0 LIMIT 0, 20
so i think what I´m looking for is this query to be executed
AND created_at NOT BETWEEN 1376555152 AND 1378369552
I think that the without method doesn't have ranges, i imagine is because you want to index portions of data and not the all data without some portion, so you can use the inverse expression.
A without like this
without: {created_at (3.weeks.ago..Time.zone.now)}
will be something like this(with a safe year for your data)
with: {created_at (Time.now.change(:year => 2012)..3.weeks.ago)}
Of course your case is a good case for this because you wouldn't have created things in the "future" if the data is consistence.

Rails where date is greater than given date query

Trying to search where movies coming out have a release date greater than today's date
Movie.where('release > ?', Date.today)
ActiveRecord::StatementInvalid: Mysql::ParseError: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'release > '2011-09-25')' at line 1: SELECT `movies`.* FROM `movies` WHERE (release > '2011-09-25')
Rails 3+ :
Movie.where('release > ?', DateTime.now)
Pre Rails 3
Movie.where(['release > ?', DateTime.now])
In recent versions of rails, you can do this:
User.where(created_at: 3.days.ago..Time.now)
See some other examples here: https://stackoverflow.com/a/24150094
Update
Rails core team decided to revert this change for a while, in order to discuss it in more detail. See this comment and this PR for more info.
I am leaving my answer only for educational purposes.
new 'syntax' for comparison in Rails 6.1 (Reverted)
Movie.where('release >': DateTime.now)
Here is a link to PR where you can find more examples.
In Ruby 2.7, you can try this:
License.where(expiration: Time.zone.today..)
SELECT "licenses".* FROM "licenses" WHERE "licenses"."expiration" >= '2021-07-06 15:12:05'
Ruby beginless/endless ranges can also be used as an out-of-the-box solution:
Post.where(id: 1..)
=> Post Load (0.4ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" >= $1 [["id", 1]]
Post.where(id: ..9)
=> Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" <= $1 [["id", 9]]
Post.where(id: ...9)
=> Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" < $1 [["id", 9]]
Note:
Replace id with your date column release
Replace value with Date.today

Ruby on Rails Query Help

I currently have the following query
User.sum(:experience, :group => "clan", :conditions => ["created_at >= ? and created_at <= ?", "2010-02-15", "2010-02-16"])
I want to return the top 50 clans in terms of experience listed from most experience to least experience with only the top 50 in experience returning. How would I modify the query to achieve that result. I know I'll need :limit => 50 to limit the query but if I add :order => "clan DESC" I get the error column "users.experience" must appear in the GROUP BY clause or be used in an aggregate function
You need to repeat the calculation in the order clause
User.sum(:experience, :group => "clan", :order=> "sum(experience) DESC", :limit => 50, :conditions => ["created_at >= ? and created_at <= ?", "2010-02-15", "2010-02-16"])