Reputation: 69
I'm retrieving user posts in batches, in order of created_at. With each batch I am taking the oldest post's created_at and using it to grab the next batch with this scope;
scope :created_before, ->(before_date) { where("created_at < ?","#{before_date}") }
This always returns the same post that the last date was taken from as part of it's result. Why is it matching as being older than itself? I tried testing this in the console for myself to see if I could discover anything and just left more confused.
p = Post.find(8227)
Grab a post for testing.
p.created_at
=> Fri, 09 Jul 2021 21:44:05 UTC +00:00
r = Post.created_after(p.created_at).order(created_at: :asc).first
The same post, ID 8227 is returned
r.created_at
=> Fri, 09 Jul 2021 21:44:05 UTC +00:00
p.created_at > r.created_at
=> false
p.created_at < r.created_at
=> false
p.created_at == r.created_at
=> true
So why is my scope thinking that r.created at is greater than p.created at? I've since decided to use IDs for this instead, but am still curious where the fault here is.
Upvotes: 0
Views: 60
Reputation: 106972
As Nitesh Purohit already wrote, you should not convert the DateTime
to String
when passing it to the query in the scope. The conversion is done internally by Rails. Therefore change your scope to this:
scope :created_after, ->(time) { where("created_at < ?", time) }
Let's have a look at the following example of how converting the DateTime
to String
affects the query that will be sent to the database.
p.created_at
#=> Sat, 10 Jul 2021 13:49:45.808179000 UTC +00:00
Page.where("created_at < ?", p.created_at).to_sql
#=> "SELECT \"pages\".* FROM \"shops\" WHERE (created_at < '2021-07-10 13:49:45.808179')"
Page.where("created_at < ?", "#{p.created_at}").to_sql
#=> "SELECT \"pages\".* FROM \"shops\" WHERE (created_at < '2021-07-10 13:49:45 UTC')"
Note that the second version that converts the DateTime
to String
drops the milliseconds from the DateTime
past to the query. This means you lose precision and this to be behavior that you observed.
Upvotes: 2
Reputation: 113
You don't need to convert date into String
try
scope :created_after, ->(before_date) { where("created_at < ?",before_date) }
Upvotes: 1