I have one table Bandwidth where I am saving user_traffic and created_at fields. I want to return user_name and created_at but I want date to be in Unix Time stamp in ruby on rails without using Query but by activerecord.
Bandwidth.all.select("user_traffic,created_at")
Above return both but in normal date format, but I want it to be in Unix
created_at: "2019-06-26 11:28:39", user_traffic: 0
I tried following and it works, but I could not get other column in this.
Bandwidth.find_by(id: 2).created_at.to_i
It return just timestamp which is perfect but how can I add other columns in this query. I think it is using model function to_i
=> 1561548975
If you don't need the relation later, you can use map to make any data format you want.
EX:
Bandwidth.all
.select(:user_traffic, :created_at)
.map{|b| [b.user_traffic, b.created_at.to_i]}
Related
Looking for a way to get all the records that are created in each month for a table
For example i need to know how to get a result like:
January: 6,
Feb: 9,
March: 10
Ideally i'm looking at using the created_at field in the database to compare against.
You can use GROUP BY and COUNT from within SQL to efficiently retrieve the data. Rails offers various options here to build an SQL query which performs aggregations and calculations with ActiveRecord::Calculations.
Assuming you have a model named Record for your records and you use MySQL / MariaDB for your database, this can be used to get the number of records per month:
records_per_month = Record.group('EXTRACT(YEAR_MONTH FROM created_at)').count
This will return a hash of Integers (corresponding to the year and month of the group so that e.g. records in May 2022 will groups under the key 202205) and the number of records within this month as values.
From your example, this would be
{
202201 => 6,
202202 => 9,
202203 => 10
}
If desired, you can then further "format" the keys, e.g.
records_per_month.transform_keys! do |year_month|
Date.strptime(year_month.to_s, '%Y%m').strftime('%B %Y')
end
Here, we parse year-month integer as a date with Date.strptime and format the date with Date#strftime to show the month name and year, e.g. "February 2022".
Imagine you have a Users table (my Rails application has one), like this:
id
name
.
.
.
created_at
updated_at
You could use this code, which would return a hash of months with the count:
users = User.all
users.group_by {|u| u.created_at.strftime("%B")}.transform_values {|v| v.count}
Returns something like:
{"September"=>33,
"August"=>1,
"October"=>1,
"February"=>55,
"January"=>185,
"May"=>4,
"December"=>145,
"June"=>8,
"November"=>19,
"March"=>51,
"April"=>27,
"July"=>5}
Explanation
created_at.strftime("%B")
This converts the date to a Month, using strftime
users.group_by {|u| u.created_at.strftime("%B")}
Creates a hash that groups the user records by the Month name, using group_by
.transform_values {|v| v.count}
Instead of a collection of records, we just want the count. We leave the key alone in the hash, and use transform_values to count the values.
I have a big query, which collects a collection of models, and I need to format the timestamps in the following manner: YYYY-MM-DDTHH:MI:SS.MSZ
So, my query looks like:
models.select("(to_char(created_at, 'YYYY-MM-DD') || 'T' || to_char(created_at, 'HH24:MI:SS.MSZ')) AS created_at").as_json
But, when I get the result, I still get created_at field as a DateTime object.
Nevertheless, if I rename the field in something else, like AS something_else, then I have my required format.
How can I fix the problem, so that it will return created_at in my format, without going through the whole collection, and formatting each model ?
UPDATE
Database I am using is PostreSQL
I traced this behaviour back to ActiveSupport::JSON::Encoder. I use the gem activesupport-json_encoder because I need the setting ActiveSupport.encode_big_decimal_as_string = false, while since Rails 4.1 they by default are encoded as strings.
Now, this Encoder is encoding created_at and updated_at fields as ActiveSupport::TimeWithZone.
Can I get rid of the latter somehow ?
My controller creates something called start_time. When I print start_time's value before it's added to a LittleClassSession hash, here's what I get:
22:45:00
Okay, it looks like a value with the type time. After it's added to the hash, I ask the controller what the :start_time value is.
#little_class_session = LittleClassSession.new({
...
:start_time => start_time
})
puts #little_class_session.start_time
Here's what it puts:
2000-01-01 22:45:00 UTC
It appears to be formatted like a datetime, but asking what the .class of the start_time attribute is returns:
Time
The LittleClassSession start_time column is a time in the table (I can verify this by checking the type in the Rails console) but was a datetime when the model was created.
What could be causing this?
While your database may support a "time" column (meaning just a time with no date information), Rails by default does not (largely because neither does Ruby's standard library -- even a Time contains date information). As such, when you assign it to your model, Rails is coercing it into the type it knows how to deal with, DateTime. So, you have a few options:
Ignore the date part of the time when you use it.
Use a gem like tod to deal with your time-only types, and follow the guidelines in the README for hooking it up to Rails.
Store start_time_hour and start_time_minutes in two separate columns, and work with them as needed (e.g, Date.current + start_time_hour.hours + start_time_minutes.minutes).
Hope that helps!
I have a DB Table for a Model entitled TradeDailyAverage. It has a date (DateTime) & averageprice (decimal) column
When I run this, I can't get the averageprice attribute to update:
newaverage = TradeDailyAverage.find_or_initialize_by_date(date)
newaverage.update_attributes :averageprice => dailyaverage
Further, when I run this, the date will show up, but the averageprice will not show up in rails console. It only shows up as blank:
newaverage = TradeDailyAverage.find_or_initialize_by_date(date)
puts newaverage.averageprice
puts newaverage.date
Is there anything special that I need to do to averageprice before I save it?
Here is all of the entire Rake Task for your reference:
averages = Trade.where('date >= ?', 7.days.ago).average(:price, :group => "DATE_TRUNC('day', date - INTERVAL '1 hour')")
# Loops through each daily average produced above
averages.each do |date, avg|
# Converts the BigDecimal to Floating Point(?)
averagefloat = avg.to_f
# Rounds the Daily Average to only two decimal points
dailyaverage = number_with_precision(averagefloat, :precision => 2)
newaverage = TradeDailyAverage.find_or_initialize_by_date(date)
newaverage.update_attributes :averageprice => dailyaverage
If you want to use find_or_initialize_by you need to think carefully about the implications. Lets take your first example:
newaverage = TradeDailyAverage.find_or_initialize_by_date(date)
newaverage.update_attributes :averageprice => dailyaverage
This should work, when the TradeDailyAverage for the given date is already in the database. It should not work however, when you get a new record back. The reason is simply because a new record is not persisted to the database. There is no way for update_attributes to update a non persisted record. You have two options here:
1.) Do not use update_attributes but assign the value and call save. This works for both, new and created records:
newaverage = TradeDailyAverage.find_or_initialize_by_date(date)
newaverage.averageprice = dailyaverage
newaverage.save
2.) Do not use find_or_initialize_by but find_or_create_by. This way if the record does not exist, a new one is directly written to the database. Now update_attributes should work because you always get persisted records back. Note that this approach has the drawback that you save records without an averageprice to the database. I would not recommend that.
The explanation above should also explain your second example:
newaverage = TradeDailyAverage.find_or_initialize_by_date(date)
puts newaverage.averageprice
puts newaverage.date
This should output the averageprice and the date for persisted records. If you get a newly initialized record back though, it will only display the date. Since you only initialized the record with a date object, there is no way that the averageprice is already set.
My issue was simply that upon saving to my database, PostgreSQL was changing the hourly time, possibly due to a timezone issue. Thus, all of my instances above were new, and I couldn't update attributes of an existing model. So, I converted my datetime data to dates, changed my date db column to date instead of datetime, and now everything is working smoothly. Yves gives some great info above though which helped me later on.
I'm passing my Rails controller a parameter that has a value of:
time = "2011-11-14T23:53:14.000Z"
For my app, I have a a database called "Reminders" with a remind_at column, which is a datetime column just like created_at and modified_at.
However I can't figure out how I should save this. I imagine it would be something like:
r = Reminder.create(:remind_at => time)
r.save
But this does not save it properly. Am I supposde to do some conversion of some sort first? Any thoughts?
Yes, you need to convert it into a Time object:
time = Time.parse("2011-11-14T23:53:14.000Z")