How to join points by line? - ruby-on-rails

I am using chartkick and gem "groupdate" in my project.
<%= area_chart SugarLevel.group_by_minute(created_at).sum(:mmol) %>
I want to keep continuing line from one point to another. I do something wrong with groupdate. If there is no data at some minute, the line has to start from previous point and has to finish at next point.
It has to be graph without gaps. Like that:

Method in gem "groupdate" group_by_something uses Hash to store a data. For example:
#hash = SugarLevel.group_by_minute(:created_at).sum(:mmol) # => {Thu, 01 Jun 2017 17:39:00 UTC +00:00=>#<BigDecimal:2add9a8,'0.77E1',18(18)>, Thu, 01 Jun 2017 17:40:00 UTC +00:00=>0, Thu, 01 Jun 2017 17:41:00 UTC +00:00=>0, Thu, 01 Jun 2017 17:42:00 UTC +00:00=>0, Thu, 01 Jun 2017 17:43:00 UTC +00:00=>0}
We can clear this hash as we want:
#hash.select{|k, v| v != 0} # Select all keys which do not consist 0
And eventually, we can put itin a view: <%= area_chart #hash %>

Related

Select object based on date range

Tech specs: ruby 2.1.5p273, Rails 4.2.3.
I have an array of Days that I want to loop through to pick the right Exits (model) that fall within a date range.
#exits has :start_date and :end_date
#days is an array of dates like:
=> [Sun, 06 Sep 2015, Sat, 12 Sep 2015, Tue, 15 Sep 2015, Fri, 18 Sep 2015, Sat, 19 Sep 2015, Sun, 20 Sep 2015, Wed, 23 Sep 2015]
I thought something like this would work:
#days.each do |day|
#exits.where(:start_date..:end_date).include?(day)
end
but I get an error:
TypeError: Cannot visit Range
What is the best way to query an object that has a date range (between two fields) by comparing it against a single date? Thanks!
You can use the following:
#days.each do |day|
exits = Exit.where('? BETWEEN start_date AND end_date', day)
# etc.
end
If you don't want to loop over them then you can do:
Event.where("start_date IN (:days) AND end_date IN (:days)", { days: #days })
or
Event.where(start_date: #days, end_date: #days)
Exit.where(day: #exit.start_date..#exits.end_date)
or
Exit.where('day >= ? AND day <= ?', #exit.start_date, #exits.end_date)
Doing SQL queries in a loop is probably a bad idea, it could be refactored to be be one call most likely. And this should happen in the controller not in the view.

Sort Nested Hash Inside Array

I have sample data like this:
[
[{"calendar"=>{:start_date=>Thu, 07 Aug 2014, :title=>"Recurring Event Test", :has_downloads=>false, :description=>"<p>Recurring content</p>\r\n", :location=>"Lunch hall", :id=>243, :end_date=>Thu, 07 Aug 2014}}],
[{"calendar"=>{:start_date=>Wed, 06 Aug 2014, :title=>"Single event", :has_downloads=>false, :description=>"<p>for date 6th</p>\r\n", :location=>"chennai", :id=>253, :end_date=>Wed, 06 Aug 2014}}]
]
Need to sort this values by start_date field.
I tried like this
sort_by {|vn| vn[:start_date]}
its showing error nil class
vn is an Array and start_date is nested inside calendar. You should do
arr.sort_by {|vn| vn[0]["calendar"][:start_date]}

ActiveSupport::JSON::Encoding::CircularReferenceError in content_tag

I have my User model with the following functions:
def self.chart_data(start = 1.weeks.ago)
total_users = users_by_day(start)
(start.to_date..Date.today).map do |date|
{
created_at: date,
users: total_users[date] || 0
}
end
end
def self.users_by_day(start)
users = where(created_at: start.beginning_of_day..Time.zone.now)
users = users.group("date(created_at), id")
users = users.select("created_at, count(id) as total_users")
users.each_with_object({}) do |user, total_users|
total_users[user.created_at.to_date] = total_users
end
end
And my View has the following line:
<%= content_tag :div, "", id: "users_chart", data: {users: User.chart_data} %>
I get the following error:
ActiveSupport::JSON::Encoding::CircularReferenceError in Static#statistics
Showing statistics.html.erb where line #5 raised:
object references itself
When i i just print the data it looks as the following:
[{:created_at=>Wed, 27 Nov 2013, :users=>0}, {:created_at=>Thu, 28 Nov 2013, :users=>0}, {:created_at=>Fri, 29 Nov 2013, :users=>0}, {:created_at=>Sat, 30 Nov 2013, :users=>0}, {:created_at=>Sun, 01 Dec 2013, :users=>0}, {:created_at=>Mon, 02 Dec 2013, :users=>0}, {:created_at=>Tue, 03 Dec 2013, :users=>{Tue, 03 Dec 2013=>{...}}}, {:created_at=>Wed, 04 Dec 2013, :users=>0}]
The only user is on 03 Dec, if there are no users there is also no error.
As you'll note in the printed data, there is a recursive reference on the 3rd:
{:created_at=>Tue, 03 Dec 2013, :users=>{Tue, 03 Dec 2013=>{...}}}
The origins come from how users_by_day is constructed. The has building references itself, by assigning an object on a given day to itself:
users.each_with_object({}) do |user, total_users|
total_users[user.created_at.to_date] = total_users
end
I think this is just an oversight in variable naming. The aggregate object you are creating is called total_users by the block, and it's the same name you give it inside the query. I believe the correct block would be this:
users.each_with_object({}) do |user, total_users|
total_users[user.created_at.to_date] = user.total_users
end
Since you need to get the total off the user variable.

Rails - A better way to parse the time with a timezone?

Time.parse returns a Time object that does not have a timezone. I would like to keep the timezone information. Is there a better way to do this then the following code?
def parse_with_timezone( string_input)
/(.*)([+-]\d\d):?(\d\d)$/.match( string_input) do |match|
tz = ActiveSupport::TimeZone[match[2].to_i.hours + match[3].to_i.minutes]
tz.parse( match[1])
end
end
The input is a string like this "2012-12-25T00:00:00+09:00". This function outputs a TimeWithZone object.
Were you looking for a specific timezone of the current local one?
# Current zone
1.9.3p194> Time.zone.parse('2012-12-25T00:00:00+09:00')
=> Mon, 24 Dec 2012 15:00:00 UTC +00:00
Console was set at UTC for above but will work for whatever you have configured
# Specific timezone
1.9.3p194> Time.find_zone('Wellington').parse('2012-12-25T00:00:00+09:00')
=> Tue, 25 Dec 2012 04:00:00 NZDT +13:00
I notice you're trying to pass +9 so as an example
1.9.3p194> Time.zone = 'Tokyo'
=> "Tokyo"
1.9.3p194> Time.zone.parse('2012-12-25T00:00:00+09:00')
=> Tue, 25 Dec 2012 00:00:00 JST +09:00
Gives you the right result.
What about the Rails Timezone API: http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html
I prefer to use Chronic for all my date/time parsing needs.

Is it possible to create a list of months between two dates in Rails

I am trying to create a page to display a list of links for each month, grouped into years. The months need to be between two dates, Today, and The date of the first entry.
I am at a brick wall, I have no idea how to create this.
Any help would be massively appriciated
Regards
Adam
Just put what you want inside a range loop and use the Date::MONTHNAMES array like so
(date.year..laterdate.year).each do |y|
mo_start = (date.year == y) ? date.month : 1
mo_end = (laterdate.year == y) ? laterdate.month : 12
(mo_start..mo_end).each do |m|
puts Date::MONTHNAMES[m]
end
end
The following code will add a months_between instance method to the Date class
#!/usr/bin/ruby
require 'date'
class Date
def self.months_between(d1, d2)
months = []
start_date = Date.civil(d1.year, d1.month, 1)
end_date = Date.civil(d2.year, d2.month, 1)
raise ArgumentError unless d1 <= d2
while (start_date < end_date)
months << start_date
start_date = start_date >>1
end
months << end_date
end
end
This is VERY lightly tested, however it returns an Array of dates each date being the 1st day in each affected month.
I don't know if I've completely understood your problem, but some of the following might be useful. I've taken advantage of the extensions to Date provided in ActiveSupport:
d1 = Date.parse("20070617") # => Sun, 17 Jun 2007
d2 = Date.parse("20090529") #=> Fri, 29 May 2009
eom = d1.end_of_month #=> Sat, 30 Jun 2007
mth_ends = [eom] #=> [Sat, 30 Jun 2007]
while eom < d2
eom = eom.advance(:days => 1).end_of_month
mth_ends << eom
end
yrs = mth_ends.group_by{|me| me.year}
The final line uses another handy extension: Array#group_by, which does pretty much exactly what it promises.
d1.year.upto(d2.year) do |yr|
puts "#{yrs[yr].min}, #{yrs[yr].max}"
end
2007-06-30, 2007-12-31
2008-01-31, 2008-12-31
2009-01-31, 2009-05-31
I don't know if the start/end points are as desired, but you should be able to figure out what else you might need.
HTH
Use the date_helper gem which adds the months_between method to the Date class similar to Steve's answer.
xmas = Date.parse("2013-12-25")
hksar_establishment_day = Date.parse("2014-07-01")
Date.months_between(xmas,hksar_establishment_day)
=> [Sun, 01 Dec 2013, Wed, 01 Jan 2014, Sat, 01 Feb 2014, Sat, 01 Mar 2014, Tue, 01 Apr 2014, Thu, 01 May 2014, Sun, 01 Jun 2014, Tue, 01 Jul 2014]

Resources