Rails - how to reference array positions in output - ruby-on-rails

I am trying to output an array in a certain way. Here is the method that gets the data:
def days
{
monday: monday,
tuesday: tuesday,
wednesday: wednesday,
thursday: thursday,
friday: friday,
saturday: saturday,
sunday: sunday
}
end
def to_ice_cube_time
[start_time, end_time, *days.compact_blank.keys]
end
The output of this is like this:
[["6:00 AM", "8:00 AM", :monday, :tuesday], ["9:00 AM", "6:00 PM", :thursday, :friday], ["8:00 AM", "4:00 PM", :monday, :tuesday]]
I am trying to loop this in the view and output the correct times on the correct days of the week. Struggling to get the individual values though.
<% scheduleevent.to_ice_cube_time.each do |timerange| %>
<p><%= timerange.start_time %> - <%= timerange.end_time %> </p>
<% end %>
That is how I would like to do it, but I get an error
undefined method 'start_time' for [["6:00 AM", "8:00 AM", :monday, :tuesday],
["9:00 AM", "6:00 PM", :thursday, :friday], ["8:00 AM",
"4:00 PM", :monday, :tuesday]]:Array
Any suggestions?

Edit:
I would look at making a helper method for displaying the data you want in the format you want like this:
#schedule_events_helper.rb
def time_slots(day)
Scheduleevent.joins(:schedtimeranges).where(day => true).order(:start_time).pluck(:start_time, :end_time)
end
Then in your view you can do something like:
<% %w(:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday).each do |day|
<%= day.to_s.titleize %>
<br>
<% time_slots(day).each do |slot| %>
<%= slot[0] %> - <%= slot[1] %>
<br>
<% end %>
<% end %>
This keeps it very obvious what you are doing to get the data and how it is being manipulated to get it to the desired format.
*** older answer below, either should work ***
You are trying to use an ActiveRecord method on an array. Arrays are referenced by their index, which starts at zero moving left to right. You could do:
<% scheduleevent.to_ice_cube_time.each do |timerange| %>
<p><%= timerange[0] %> - <%= timerange[1] %> </p>
<% end %>
Per your comment that this references a previous answer you should include that link in your question and explain that. I still think you should rework the original query to get the data in the format you want rather than all of these twists and turns. As soon as things are put into an array format you loose a lot of the obvious data meaning. You want a hash output like
{monday: [["6:00 AM", "8:00 AM"], ["8:00 AM", "4:00 PM"]], tuesday: [["4:00 AM", "8:00 AM"], ["6:00 AM", "4:00 PM"]]...}
Given your previous post:
days_of_week = %w(:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday)
output = {}
days_of_week.each do |day|
output[day] = Scheduleevent.joins(:schedtimeranges).where(day => true).order(:start_time).pluck(:start_time, :end_time)
end
this should give you an output of
{monday: [['6:00 AM', '11:00 AM'], ['8:00 AM', '4:00 PM']...],
tuesday: [['4:00 AM', '11:00 AM'], ['8:00 AM', '4:00 PM']...],
...}
And easily represented as: #note I changed this to a simpler form
<% output.each do |day,times| %>
<%= day.to_s.titleize %>
<br>
<% times.each do |slot| %>
<%= slot[0] %> - <%= slot[1] %>
<br>
<% end %>
<% end %>
Think about how you want the final data structured and try to make the code produce that as simply as possible. There are many other ways to tweak by writing instance methods or helper methods to format the output of the data.

The error that you are getting is because you are trying to access a position of an array as if it where a method.
Either you just print out timerange[0]
or you make your to_ice_cube_time method return a Hash so you can read it like timerage[:start_time]
Or even, you could use the Hashie gem to wrap it and read it like it is.
If you are using the new Ruby syntax it would look like this
def to_ice_cube_time
Hashie::Mash.new({ start_time:, end_time:, days: *days.compact_blank.keys })
end

Related

trouble making an "if" statment with time.now on ruby on rails

I'm trying to display a message depending on the time of the day and I currently have this piece of code:
<% if Time.now >= "7:00" and Time.now <= "14:00" %>
Good Morning <%= current_user.nome %>! <br>
<% else %>
Good Afternoon <%= current_user.nome %>!
<% end %>
It's currently 14:30 and the page still displays Good Morning (username), when it should display Good Evening (username)
Is my code wrong?
How do I fix this?
try:
<% if Time.now >= Time.parse("7:00") and Time.now <= Time.parse("14:00") %>
Good Morning <%= current_user.nome %>! <br>
<% else %>
Good Afternoon <%= current_user.nome %>!
<% end %>
Note: Time.now will return time object while "7:00" is a string, so you need to convert string time to time object and can compare.
You can write like this Instead of Parsing the Time you can write simply
Solution : 1
<% if Time.now.hour >= 7 && Time.now.hour <= 14 %>
Good Morning <%= current_user.nome %>! <br>
<% else %>
Good Afternoon <%= current_user.nome %>!
<% end %>
Solution : 2
you can write less code via using ternary operator
(0..11).include?(Time.now.hour) ? "Good Morning <%= current_user.nome %>" : Good Afternoon <%= current_user.nome %>
I think this is worth it to be a helper method:
# in app/helpers/application_helper.rb
def greeting(name)
greeting = (7..13).cover?(Time.current.hour) ? 'Good Morning' : 'Good Afternoon'
"#{greeting} #{name}".strip
end
And in your view:
<%= greeting(current_user.nome) %>!
Another more detailed version that supports uneven times might look like this:
def greeting(name)
greeting = case Time.current.to_s(:time)
when ('05:00'..'11:59') then 'Good Morning'
when ('12:00'..'17:59') then 'Good Afternoon'
when ('18:00'..'21:59') then 'Good Evening'
else 'Good Night'
end
"#{greeting} #{name}".strip
end
I would use helpers to store methods and keep views plain.
class ApplicationHelper
def greeting
"Good #{time_greeting} #{current_user.nome}"
end
def time_greeting
return "Morning" if Time.now.hour.between?(7, 13)
"Afternoon"
end
end
Then you may only use greeting method in your views:
<%= greeting %>
I'd use a helper:
def morning?(t = Time.current)
t.between? t.change(hour: 7), t.change(hour: 14)
end
t is a time instance, defaulting to the current time, for example:
t = Time.current
#=> Tue, 04 Jul 2017 16:30:09 CEST +02:00
change sets one or more of the time's elements. If only :hour is specified, the "smaller" units like minutes and seconds are set to 0:
t.change(hour: 7) #=> Tue, 04 Jul 2017 07:00:00 CEST +02:00
t.change(hour: 14) #=> Tue, 04 Jul 2017 14:00:00 CEST +02:00
between? finally checks if t is between these values.
Passing the current time as an argument makes it easier to test the method:
morning? Time.parse('06:59') #=> false
morning? Time.parse('07:00') #=> true
morning? Time.parse('14:00') #=> true
morning? Time.parse('14:01') #=> false
Usage:
<% if morning? %>
Good Morning <%= current_user.nome %>!
<% else %>
Good Afternoon <%= current_user.nome %>!
<% end %>

Ruby on Rails only show data value once if there are more than one of the same

In my ruby on rails application I am currently displaying the date and time each film is shown through:
<% if not #film.showings.blank? %>
To book click on a time below:</br>
<% #film.showings.each do |showing| %>
<%= showing.show_date.strftime("%A %e %B %Y") %># <%= showing.show_time.strftime("%H:%M") %><br>
<% end %>
<% else %>
<p>There are currently no showings for this film.</p>
<% end %>
And this displays data like the following:
Sunday 25 January 2015 # 12:00
Sunday 25 January 2015 # 16:00
Monday 26 January 2015 # 11:00
Monday 26 January 2015 # 22:00
Tuesday 27 January 2015 # 22:00
Wednesday 28 January 2015 # 11:00
Wednesday 28 January 2015 # 12:00
Wednesday 28 January 2015 # 16:00
Wednesday 28 January 2015 # 19:30
But what I want to be able to do is if the date is repeated then it only shows it once and repeats the time, so for example the date Sunday 25 January 2015 would be shown as:
Sunday 25 January 2015 # 12:00 16:00
You should group records by date and join hours.
<% if not #film.showings.blank? %>
To book click on a time below:</br>
<% #film.showings.group_by{|showing| showing.show_date.strftime("%A %e %B %Y") }.to_a.each do |showing| %>
<%= showing.first %># <%= showing.last.map{|s| s.show_time.strftime("%H:%M")}.join(' ') %><br>
<% end %>
<% else %>
<p>There are currently no showings for this film.</p>
<% end %>
You could place a function like this in helpers or a decorator if you are using them. I'm assuming you pass in the showings from #file.showings. This will return an array that is how you want that you could loop over in the view and display.
def show_times(showings)
showings.each_with_object({}) do |showing, hash|
key = showing.show_date.strftime("%A %e %B %Y")
hash[key] ||= []
hash[key] << showing.show_time.strftime("%H:%M")
end.map do |date, times|
"#{date} # #{times.join(' ')}"
end
end
Given an array of datetime objects, you can use the following code to extract a nested hash of date and time showings. It probably best lives inside your Film model.
def showings_hash
showings.pluck(:show_time).map {|datetime| datetime.to_date}.uniq.map{|date| {date => dates.select{|datetime| date == datetime.to_date}}}
end
This returns:
- 2015-01-12:
- !ruby/object:DateTime 2015-01-12 18:00:00.000000000 Z
- !ruby/object:DateTime 2015-01-12 19:00:00.000000000 Z
- !ruby/object:DateTime 2015-01-12 20:00:00.000000000 Z
- 2015-01-13:
- !ruby/object:DateTime 2015-01-13 20:00:00.000000000 Z
You can then iterate through each showing date in the view like so:
<% #film.showings_hash.each do |showing_date| %>
<li>
<%= showing_date %>
<% showing_date.each do |showtime| %>
<%= showtime.strftime("%H:%M") %>
<% end %>
</li>
<% end %>

Removing eg. (UTC, +0100, +0200, +seconds ) from the timezone RAILS

I'm trying to learn some rails and it's moving forward, but something that bothers me is as the title says, the ending of the timestamp. As im swedish i modified it to display my correct timezone.
EG: 2014-08-20 13:24:51 +0200
But what i want to see is 2014-08-20 13:24
To display the time for each post i use
<% #blog_posts.reverse_each do |blog_post| %>
<h3><%= blog_post.title %></h3>
<p> <%= blog_post.created_at.to_s %> </p>
<p>
<%= simple_format(blog_post.body) %>
</p>
<% end %>
Anyone with a simple idea to solve the issue?
In Rails you can use the to_time function on a string to convert it into a Date object:
> '2014-8-20 14:27:46'.to_time.strftime('%B %e at %l:%M %p')
=> "August 20 at 2:27 PM"
strftime Format Directives:
%B Full month name
%e Day of the month
%l Hour of the day
%M Minute of the hour
%p Meridian indicator (AM/PM)
Try
<%= blog_post.created_at.to_s %>
Or use strftime:
<%= blog_post.created_at.strftime("%Y-%m-%d %H:%M") %>
You can use to_formatted_s method:
<%= blog_post.created_at.to_formatted_s(:db) %>
It will show seconds also. If you want only date, hours and minute, try:
<%= blog_post.created_at.strftime("%Y-%m-%d %H:%M") %>
Look at method strftime from ruby class Time
<%= blog_post.cteated_at.strftime("%Y-%m-%d %H-%M") %>
This link could be helpfull too
Strfti.me
EDIT:
For localize your time you must use localize or l => <%= l post.created_at %>
first download yours locale yml file from Rails locale files
copy the raw file to the conifg/locales.
In this file you could set yours default strftime:
formats:
default: "%B %e at %l:%M %p"
Then in your application.rb
config.i18n.default_locale = :pl // for me is pl :)
and finally in your view
l blog_post.created_at
Hope that help you :)
try this..
<%= #user.created_at.to_date.to_formatted_s(:long_ordinal)%> => July 5th, 2014
<%=#user.created_at.strftime("%b %d,%Y") %> => Jul 05,2014
...whichever u prefer

How do I split the value returned by created_at?

I am trying to split the value returned by the created_at method.
I am taking an object (item) and getting the time it was created at. I don't want the whole result and I am only interested in the day, month and year. How can I get this to work?
<% #items_in_basket.each do |item| %>
<% splliter = item.created_at.split(" ") %>
<% time = #splliter[0] %>
I get this as a result:
undefined method 'split' for Wed, 31 Jul 2013 16:44:37 UTC +00:00:Time
created_at returns an instance of ActiveSupport::TimeWithZone which you can simply call day, month, or year on to get those parts of the date. Example:
<% #items_in_basket.each do |item| %>
Day: <%= item.created_at.day %>
Month: <%= item.created_at.month %>
Year: <%= item.created_at.year %>
<% end %>
This approach will be much more reliable than parsing the string format returned by to_s.
Try converting the date to string first before using the string method split (http://ruby-doc.org/core-2.0/String.html#method-i-split).
<% splliter = item.created_at.to_s.split(" ") %>
The reason you are getting that error is because Time (http://www.ruby-doc.org/core-2.0/Time.html) class does not have split method.

Having trouble parsing and spacing date/fixnum objects

I'm building a small app that takes things entered into an input field and displays them directly below that input field when entered.
My goal with this code is to separate those entries by date so that all things posted on June 1 are posted with one line break between them and the first entry of June 2 has 2 spaces between it and the entries from June 1.
This is my code and it's not acting as planned but I can't figure out why, I think it stems from line 3 and something I'm doing incorrectly. (Note: I'm aware this doesn't account for changes in month or year yet. I'll get to that once I figure out proper date spacing)
<% for i in (0..(#allLessons.count-1)) %>
<b><%= #date[i].created_at.strftime('%b %d')%></b><br/>
<% if #date[i].created_at.strftime('%d') == #date[i-1].created_at.strftime('%d') %>
<%= #date[i].created_at.strftime('%d') %> <br />
<% else %>
<%= #date[i].created_at.strftime('%d') %><br /><br />
<% end %>
<% end %>
From the controller:
#allLessons = Lesson.all
#date = Lesson.find(:all, :order => 'created_at ASC')
Any help you could lend on this would be hugely appreciated!
Blocks and iterators are where it's at.
#allLessons = Lesson.order('created_at ASC')
#dates = #allLessons.group_by { |lesson| lesson.created_at.beginning_of_day }.sort
<% #dates.each do |date, lessons| %>
<% lessons.each do |lesson| %>
<b><%= lesson.created_at.strftime("%d") %></b><br />
<% end %>
<br />
<% end %>
Annotated
First we get all of the lessons together. This is equivilant to find(:all, :order => 'created_at ASC'), but I like this newer, compact syntax
#allLessons = Lesson.order('created_at ASC')
Then we group them all together into a hash where the key is the date and the value is an array of records that were created on that day. beginning_of_day converts a DateTime into a Date where the time is set to 00:00:00. So, 2012-05-25 18:00 becomes 2012-05-25 00:00:00. This is so we can group the dates themselves without the time getting in the way
#dates = #allLessons.group_by { |lesson| lesson.created_at.beginning_of_day }.sort
#dates is now a hash where the keys are dates and the values are arrays of lessons from that date. for example, { '2012-05-24 00:00:00' => [ lesson_1 ], 2012-05-25 00:00:00' => [ lesson_2, lesson_3 ]
We then pass the hash into a block, where the key is the date, and the value is the array of lessons. This is saying, for each date...
<% #dates.each do |date, lessons| %>
Give me the lessons that belong to that date. And for each of those...
<% lessons.each do |lesson| %>
print out the date of the lesson
<b><%= lesson.created_at.strftime("%d") %></b><br />
<% end %>
before moving on to the next date, print a <br />
<br />
<% end %>

Resources