Active Record order by current day - ruby-on-rails

Im having an issue sorting an array by the current date.
my database has a field called day
day has the days of the week eg: Monday, Tuesday, etc.
I am trying to sort my index view page by the current day.
I would like to do somehting like this in my controller,
#happies = Happy.where(id: #search.results.map(&:id))
.page(params[:page])
.where(:day => Date.today.strftime('%A').capitalize.to_s)
but instead of returning only happies with the day Monday I would want to order by day where day is equal to the current day.
I also thought about doing this in my view
with something like
<% #happies.sort_by(:day => Date.today.strftime('%A').capitalize.to_s).each do |happy| %>
the above does not work but im trying to get accross what I wan to achieve. Any ideas on how to implement this?
Maybe there is an activeview helper?

If you were not paginating, you could sort the results in plain ruby like this:
day_order = %w(Tuesday Wednesday Thursday Friday Saturday Sunday Monday)
#happies = #happies.sort_by{|happy| day_order.index(happy.day)}
sort_by takes a block that returns the value to sort by.
However, you appear to be paginating using will_paginate. That's fine but it makes things more complicated.
The pagination necessarily happens in the database via limit and offset (so as to avoid returning the entire contents of the table to the Rails process). Therefore you want the sorting to also happen in the database. If you were to sort in ruby (as above) you would be sorting after pagination, meaning the first page would give you essentially random results, and then you'd sort them. Probably not what you want.
Long story short, you probably want to use order instead of sort_by, and I'm going to have to dip into SQL for this one:
#happies = Happy.where(id: #search.results.map(&:id))
.page(params[:page])
.order("CASE day WHEN 'Tuesday' THEN 0 " \
"WHEN 'Wednesday' THEN 1 " \
"WHEN 'Thursday' THEN 2 " \
"WHEN 'Friday' THEN 3 " \
"WHEN 'Saturday' THEN 4 " \
"WHEN 'Sunday' THEN 5 " \
"WHEN 'Monday' THEN 6 END")
If you want to avoid SQL, perhaps it is possible to use Arel for this, I'm not sure.
Edit
I see now you want to start with the current day, i.e. not hardcoded as Tuesday like I did. To fix my SQL version - and borrowing a bit from #Snarf's answer - you could do this:
days = %w(Monday Tuesday Wednesday Thursday Friday Saturday Sunday)
days.rotate!(days.index(Time.zone.now.strftime("%A")))
case_pieces = days.each_with_index.map do |day, i|
"WHEN '#{day}' THEN #{i}"
end
#happies = Happy.where(id: #search.results.map(&:id))
.page(params[:page])
.order("CASE day #{case_pieces.join(' ')} END")
Another thought
If I was writing the app myself, I would be tempted to store the day as an integer from 0 to 6, instead of as a string. Then you could order using the modulo operator, something like this:
days = %w(Monday Tuesday Wednesday Thursday Friday Saturday Sunday)
day_offset = days.index(Time.zone.now.strftime("%A"))
#happies = Happy.where(id: #search.results.map(&:id))
.page(params[:page])
.order("(day - #{day_offset} + 7) % 7")

Here's a pure ruby solution.
days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
days.rotate(days.index(Time.now.strftime("%A")))
#=> ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

Basically the same as #Snarf - this is only ruby and will not support pagination
today = Date.current.strftime('%A')
# => Monday
days = Date::DAYNAMES
# => ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
today_index = days.index(today)
# => 1
#ordered_days = days.rotate(today_index)
# => ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
#happies = Happy.where(id: #search.results)
<!-- view -->
<% #ordered_days.each do |day| %>
<!-- in memory selection from the #happies collection, could be emtpy -->
<% occurring_on = #happies.select { |happy| happy.day == day } %>
<%= day %>
<% occuring_on.each do |happy| %>
<%= happy %>
<% end %>
<% end %>

Related

Populating a f.select of day names that relate to the last 6 days

I'm trying to populate a f.select with the last 6 days using day names. I want the field presented by their day names but internally I want to save the date previous to NOW that the day name represents.
#days = [ ]
6.downto(0).each do |number|
#days << number.days.ago
end
This will give me the last days which is the data I want to be able to select to save.
I want the select field populated with those dates, but with the day names only.
If I do this....
#days.each do |d|
#daynumber = d.wday
end
Then I get ...
Date::DAYNAMES[#daynumber]
..... ERROR..It cant implicitly convert array into integer.
No clue.
You're on the right track, but you need to iterate over that array to get the dayname lookup to work. Luckily, Ruby has awesome built-in methods to do exactly that, and Enumerable#map is perhaps the most useful.
Try this:
>> #days.map { |d| Date::DAYNAMES[d.wday] }
=> ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
Or if you don't need the interim array for some other reason, you can do the whole thing in a single line like this:
>> day_names = 6.downto(0).map { |number| Date::DAYNAMES[number.days.ago.wday] }
=> ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
I have figured it out while researching map and collect.
<%= f.select :backup, #days.collect { |d| [ Date::DAYNAMES[d.wday], d ] } %>
This is working! Thank you community for helping me correct my question and pointing towards an answer.

Ruby on Rails - find Next and previous date based on param

I have added activity_logs to my application and I show #activities based on giving param_date to url.
My link/path looks like:
http://localhost:3000/users/activity_logs?param_date=2016-09-12.
I do much like to add Next day & Previous day on same page. How can I find the Next day & Previous day based on the date I have on param_date.
Ex: = link_to 'Next day', activity_logs_path(param_date: date)
So basically if param_date is 2016-09-30, Next Day would be: 2016-10-01 and Prev day: 2016-09-29
try this:
prev_data = (Date.parse(params[:param_date]) -1).strftime('%F')
next_data = (Date.parse(params[:param_date]) +1).strftime('%F')
Ruby's date class has a next_day and a prev_day method:
Just parse the date from the params in your controller
#date = Date.parse(params[:param_date])
and build the links like this in your views
link_to('Next day', activity_logs_path(param_date: #date.next_day))
link_to('Previous day', activity_logs_path(param_date: #date.prev_day))

Ordinalize in embedded ruby

Is there a quick way to be able to ordinalize the following code?
<%= time_tag(Date.today, :format=>'%A %d %b') %>
The current output reads
Tuesday 18 Feb
I want to ordinalize the date to show
Tuesday 18th Feb
Any suggestions?
You can use Date::DATE_FORMATS to add a new customized format, and Integer.ordinalize to get the day ordinal:
Date::DATE_FORMATS[:month_ordinal] = lambda { |date|
date.strftime("%A #{date.day.ordinalize}, %B")
}
>> Date.today.to_formatted_s(:month_ordinal)
=> "Tuesday 18th, Feb"
Write as below using #ordinalize :
<%= time_tag(Date.today, :format=>"%A #{Date.today.day.ordinalize} %b") %>

Rails 12 hour AM/PM range for a day

This is a really simple question, and it's probably been asked and answered before, but I haven't been able to find anything.
Anyway, I need a range/array for 12 hour time, so like 12AM - 11AM, 12PM - 11PM. You probably get the gist of it. Right now I'm trying to do an absurdly complicated method involving mapping AM onto one array, PM onto another one, and then joining the two arrays together. There has to be an easier way to do this.
I know about Rails time_select, but I need a different format than what it provides. Any suggestions?
Clarification: So what I'm looking for is the 12-hour clock, with AM and PM. If I wanted a 24-hour clock, I could just do (0..24), and be done. But the 12-hour clock goes from 12-11 AM, and then goes from 12-11 PM. I'm pretty sure someone has done this before.
I agree with #MrYoshi's comment, the easiest way of formatting a date is .strftime(),
see RubyDoc for all possible options
Example:
Time.now.strftime("%I:%M %p")
output: HH:MM AM
Or what you literally asked for:
Time.now.strftime("%I:00")
output: HH:00
As you mentioned time_select I assume you want to offer time as a user selectable range, so try these options for time_select(more options):
time_select 'game', 'game_time', {:minute_step => 60, :ampm => true}
also this previous question: Time select form helper with 12 hour format for Rails 3?
Rails does this built in
<%= f.time_select :start, {ampm: true} %>
http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-time_select
I know this has already been answered awhile ago with the built in. But I needed a custom function to get these values and wrote this:
times = {"12 AM" => 0}.merge!(1.upto(11).collect { |n| {"#{n} AM" => n} }.reduce(Hash.new, :merge)).merge!({"12 PM" => 12}).merge!(1.upto(11).collect { |n| {"#{n} PM" => n + 12} }.reduce(Hash.new, :merge))
This yields:
{"12 AM"=>0, "1 AM"=>1, "2 AM"=>2, "3 AM"=>3, "4 AM"=>4, "5 AM"=>5, "6 AM"=>6, "7 AM"=>7, "8 AM"=>8, "9 AM"=>9, "10 AM"=>10, "11 AM"=>11, "12 PM"=>12, "1 PM"=>13, "2 PM"=>14, "3 PM"=>15, "4 PM"=>16, "5 PM"=>17, "6 PM"=>18, "7 PM"=>19, "8 PM"=>20, "9 PM"=>21, "10 PM"=>22, "11 PM"=>23}

display posts by month/year ruby

Not sure where to start with this so here goes.. I am building a small blog in which the date of each post is displayed, overtime there will be many blog posts per month, for which i would like to group together by the month it was published.
I want to display it like this in the view
Archives
January 2013
February 2013
March 2013
etc
When i click on a given month the idea is it will take me to all the posts that where published within that month.
So far I can group all the posts by month and year
#posts_by_month = Post.all.group_by { |post| post.created_at.strftime("%B %Y") }
In my view i then render like so
<% #posts_by_month.each do |m| %>
<%= m %>
<% end %>
Which returns this in the view
["July 2013", [#<Post id: 1, title: "Ruby News", comments: "dsfdsfdsfdsfdsfds", category_id: 1, user_id: 1, created_at: "2013-07-26 07:10:25", updated_at: "2013-07-26 07:19:27", photo_file_name: "pf-7.jpg", photo_content_type: "image/jpeg", photo_file_size: 162495, photo_updated_at: "2013-07-26 07:19:26">]]
So at the moment i have a hash where the month/year is the key and then all my posts in an array, is that correct?
All i want to display is the Month/Year and then click that month to be taken to all the posts for that month
Any help appreciated
EDIT
ok silly me, forgot my basics on key/value pairing, i have got just the date to display
<% #posts_by_month.each do |m,p| %>
<%= link_to m %>
<% end %>
Now i just need to be able to click the link to see all posts for that month
You could do
= link_to m, posts_path(:month => m)
Now in posts#index, fetch the posts based on params[:month]
if params[:month]
date = Date.parse("1 #{params[:month]}") # to get the first day of the month
#posts = Post.where(:created_at => date..date.end_of_month) # get posts for the month
else
#posts = Post.all
end

Resources