I have model in which I keep track of the field updated_at.
Is there a way I can track the previous updated_at?
For example
updated_at = A (where A is an actual datetime stamp)
Some work is done then save is called
updated_at = B (where B is an actual datetime stamp)
Is there a way I can access the previous updated_at i.e. A?
If you have the object available, then you can call:
object.previous_changes
This would return you a hash as follows showing which attributes have been changed:
{"name"=>["foo", "bar"], "updated_at"=>[Tue, 19 Apr 2016 08:19:40 UTC +00:00, Mon, 25 Apr 2016 10:49:47 UTC +00:00]}
Refer:
previous_changes
Please have a look ActiveModel::Dirty module:
object.updated_at # returns current value
object.updated_at_changed? # returns true or false if value has changed
object.updated_at_was # return last value
object.updated_at_change
Or
If you wants to track all changed values you can use Paper Trail Gem.
It will be useful if you use paper trail gem.
It will persist the previous record on disk which may affect your app performance.
Better way to implement an in-memory solution to store the previous records.
Related
Hi I am using this code bellow
Companion.where(companion_type: 1).joins(:tasks).where(tasks: {status: 3}).group_by_month(:created_at).size
and i am having a data looks like this
Jan, 2017 => 89
.
.
.
Aug, 2021 => 300
But i need data's above from Jan, 2019
Is there any nice ways to solve it out?
If you are only interested in Jan 2019, then you don't need to pull all the Companion table, and then group them by month. Instead, select only those in the month of interest...
Companion.
where(companion_type: 1).
joins(:tasks).
where(tasks: {status: 3}).
where("MONTH(tasks.created_at) = 1 AND DAY(tasks.created_at) = 19").
count
I assume that it's the created_at of tasks that you want to filter, vs. the created_at of companions, is that right?
Also, it's better to use count than size because that is directly inserted into the sql, as opposed to instantiating all the objects from Jan, 2019 and then applying .size to the result.
Why isn't Time.current equal to its parsed equivalent?
current = Time.current
# Wed, 16 Sep 2015 17:10:56 CEST +02:00
parsed = Time.zone.parse('16 Sep 2015 17:10:56')
# Wed, 16 Sep 2015 17:10:56 CEST +02:00
current == parsed
# false <= What ?!
current.to_i == parsed.to_i
# true
Ticket.create(datetime: current)
# ...
Ticket.find_by_datetime(parsed)
# nil <= Why ?!
I'm actually having trouble with this in a Ruby on Rails application where I try to find a record based on a datetime attribute that has been parsed, like shown on the last lines.
I really don't get it. Time zones are the same, times are the same down to seconds. What's happening here?
Moreover, how should I proceed to find a record based on a parsed datetime?
They should not be the same:
current.to_f #=> 1442417032.6567826
parsed.to_f #=> 1442417032.0
When parsing, you miss milliseconds.
Thanks everyone for the help. I hope you don't mind but since pieces of the final answer are scattered across multiple answers I will answer my own question building on what you all said.
So as for why the dates are different, it's because of the milliseconds missing in the parsed datetime. As #dimakura mentioned.
current.to_f #=> 1442417032.6567826
parsed.to_f #=> 1442417032.0
Then the answer about how could we fetch the Ticket record based a the parsed datetime.
First it's important to know this will be relevant only for PostgreSQL (my case) or other databases that actually store milliseconds. Thanks to #sjagr for mentioning this.
So we have to query for a range from parsed to parsed + 1 second, like #Stefan explained:
Ticket.where(datetime: parsed...parsed+1).first
And if we have control on the Ticket creation, we could also remove the millisecond precision before saving the the database. Thanks to #sjagr for providing an easy way to do that.
current = Time.current
Ticket.create(datetime: current.change(usec: 0))
Thanks everyone !
It's because they are not equal, they differ by parts of the second. What you see in the console is the result of inspect method called on those dates, which by default, drop any sub-second parts.
Sorry if that question sounds strange, but I'm diving into Rails and I'm still learning the jargon. Basically, I'm trying to create a single-pass query that uses the value of one of the model's attributes in a calculation in the query (assuming that's even possible).
I have a Tournament model that has a start_date attribute that is a DateTime object. I'm trying to create a query that returns all the Tournaments that have a start_date no older than 1 hour + the length of the tournament, or put another way, all tournaments that haven't yet started or have started, but haven't ended longer than an hour ago. My current query, which doesn't work, looks like this...
validTourneys = Tournament.where("start_date > (? - duration_in_mins)", (DateTime.now.utc - 1.hour))
where duration_in_mins is an integer attribute of the Tournament model, but this query doesn't work and it seems to be returning all the Tournaments all the time. I'd like to include duration_in_mins in the (DateTime.now.utc - 1.hour) part of the calculation, but I don't know how to reference it, which is why I included it in the string part of the query, hoping that would work. Am I at least on the right track?
I should mention I'm using SQLite for development and PostgreSQL for production.
Thanks for your wisdom!
The problem is that if you subtract minutes from a DateTime object, you are not subtracting minutes but days.
# This works as expected
dt = DateTime.now # Thu, 28 Apr 2011 09:55:14 +0900
an_hour_ago = dt - 1.hour # Thu, 28 Apr 2011 08:55:14 +0900
# But, this does not...
two_hours_in_minutes = 120
two_hours_ago = dt - two_hours_in_minutes # Wed, 29 Dec 2010 09:55:14 +0900
In the last example 120 days are subtracted instead of minutes. This is probably also happening in your query. You have to convert duration_in_minutes to days and then subtract.
I don't know enough about SQL to answer your question directly (I think this will probably also depend on what database you're using, so you might want to mention that).
Have you considered, though, having start_date and end_date as DateTime columns instead of start_date and duration_in_mins? If this is going to be a common query, that would certainly make it more performant, as well as making your code easier to read and understand.
This query will only work if your database is smart enough to know how to add (what I am assuming) is a DateTime and and integer. And I can't think of a database that will do that correctly the way you have it coded. No database will assume minutes. Some might do ticks, seconds, or days.
This part of the calculation
(? - duration_in_mins)
is going to happen on the database, not in Ruby-land.
I'm a bit confused about timezones in rails. I want my rails app to use British Summer Time (like daylight savings in the US) for the timestamps set in updated_at and created_at in my models. I changed my environment.rb to say
config.time_zone = 'London'
The ubuntu server my app is on seems to use BST for it's time: in the command line, for example, if i type 'date' i get the current time (not offset by an hour). In the rails console, i see the following:
>> time = Time.now
=> Wed Oct 27 16:29:17 +0100 2010
>> time.zone
=> "BST"
All fine. However, if i make a new AR model object and save it, the timestamps are from an hour ago. So, it looks like this is using UTC. Now, i can see the logic in this: since the timestamps might be used in the model logic, you want them to be based on an unvarying yardstick time, ie UTC. But, this is a weird bit of behaviour that i don't understand:
#change a record and save it
>> someobj.save
=> true
#object's updated_at is one hour ago
>> someobj.updated_at
=> Wed, 27 Oct 2010 15:34:22 UTC +00:00
>> Time.now
=> Wed Oct 27 16:34:31 +0100 2010
#however, Time.now - object's updated at is just a few seconds.
>> Time.now - someobj.updated_at
=> 15.305549
So, before doing the subtraction, updated_at is converted into the current time zone.
The reason i want to show the date in the current time zone is just for status reports etc in the views: if someone updates something i want them to see that it was updated '1 minute ago' not 'one hour ago'.
Can anyone unconfuse me? cheers, max
EDIT: My immediate problem, of showing the right time in the status, is solved by using the 'time_ago_in_words' helper, which adjusts for time zone. I'd still like someone to explain what's going on with the timestamps though :)
Timestamps are stored in UTC by default, and this is probably the best way to do it. If you move from one server environment to another, you don't want all of your times shifting around just because you switched time zones.
If you want to know what the timestamp is in your local time zone, you just have to ask for it that way:
someobj.updated_at.localtime
Note the offset listed at the end of the times -- the first offset is 0, the second is 1. When the time calculation occurs, the offset is included automatically, so that the subtraction gives you the correct result. someobj.updated_at and Time.now each displays its value in a different time zone, so they are really only 9 seconds apart, not 1 hour and 9 seconds.
The behavior I'm observing with the Mongoid adapter is that it'll save 'time' fields with the current system timezone into the database. Note that it's the system time and not Rail's environment's Time.zone. If I change the system timezone, then subsequent saves will pick up the current system timezone.
# system currently at UTC -7
#record.time_attribute = Time.now.utc
#record.save
# in mongo, the value is "time_attribute" : "Mon May 17 2010 12:00:00 GMT-0700 (QYZST)"
#record.reload.time_attribute.utc? # false
Try setting the use_utc mongoid config parameter to true.
It tells Mongoid that you want to return times in UTC:
http://github.com/durran/mongoid/blob/master/lib/mongoid/config.rb#L22