I have a site that uses ruby (rhtml) files which I am not used to editing (more used to php). I only have access to these files to edit (so not the back-end).
In the database I have a date that I can display using:
<%= zp.date %>
which will display e.g. 14/10/2010
I can display today's date using:
<%= Date.today.strftime("%Y%m%d") %>
which will display 20160122.
What I'm trying to work out is how I can compare the dates and echo the difference and in turn display something different.
e.g.
compare <%= zp.date %> and <%= Date.today.strftime("%Y%m%d") %>.
If days difference is less than 20 echo XXX
else
If days difference between 20 - 40 echo XXX
else
If days difference between 41 - 60 echo XXX
Any help would be appreciated (links etc), code examples would be greatly appreciated.
Again to clarify I can only edit the rhtml.
Dates are directly comparable with if-statements, and computing the difference will show you the number of days between them. Assuming zp.date is in the past:
<% date_difference = Date.today - zp.date %>
<% if date_difference < 20 %>
...
<% elsif date_difference <= 40 %>
...
<% elsif date_difference <= 60 %>
...
<% else %>
Difference is greater than 60
<% end %>
Note the <% %> tags, which are used for if-logic and internal Ruby code - basically any expression that shouldn't be output (thanks #QPaysTaxes), instead of <%= %> which is the output tag.
If you don't know whether zp.date is in the past or future, you can use the abs method on the result:
<% date_difference = (Date.today - zp.date).abs %>
And if zp.date isn't actually a Date object, then parse it:
<% date_difference = (Date.today - Date.parse(zp.date)).abs %>
Older Ruby versions will need strptime when the date string is ambiguous:
<% date_difference = (Date.today - Date.strptime(zp.date, '%d/%m/%Y')).abs %>
Related
I'm looping through an array of records like this:
#products = Product.where(category_id: #categories).order(updated_at: :desc)
<% #products.each do |product| %>
<%= #product.title %>
<%= #product.price%>
<% end %>
And now I wan to to mark the newest records as new releases:
<% #products.each do |product| %>
<% if product.created_at <= product.created_at + 2.days %>
New release
<% end %>
<%= #product.title %>
<%= #product.price%>
<% end %>
But instead of going through each product and marking which ones is new (according to the if condition I have), it just takes the first record which returns true to the if condition and marks all of the products as new.
Any idea why this is happening and how I can fix this?
Your logic is incorrect - this line:
if product.created_at <= product.created_at + 2.days
will always be true (you're comparing a date with itself), so everything will always be marked as a new product.
Did you mean to compare the created_at date with the current date instead? If you wanted to check if a product created less than two days ago, use product.created_at >= 2.days.ago.
<p>
<strong>Dob:</strong>
<%= #student.dob %>
<%= today = Date.today%>
<%= d = Date.new(today.year, #student.dob.month, #student.dob.day)%>
<%= age = d.year - #student.dob.year - (d > today ? 1 : 0)%>
<strong>Age:</strong>
<%=age%>
</p>
So this code successfully takes the date of birth of a student and displays age. However when looking at the webpage it displays all of the calculations. How do I get it so it just displays age?
Try this:
<p>
<strong>Dob:</strong>
<%= #student.dob %>
<% today = Date.today%>
<% d = Date.new(today.year, #student.dob.month, #student.dob.day)%>
<% age = d.year - #student.dob.year - (d > today ? 1 : 0)%>
<strong>Age:</strong>
<%= age %>
</p>
The problem is that you're using the equals sign (=) at the beginning of the lines of your erb template which contains the variable assignments and calculations, which prints the result of the evaluated Ruby code into your template.
Keep in mind though, that this kind of logic should not be in your view. Views are meant only to present html markup filled with information provided by your models. In this case, I think it would be a lot better to have this logic in your student model, like this:
def age
d = Date.new(Date.today.year, dob.month, dob.day)
d.year - dob.year - (d > Date.today ? 1 : 0)
end
And then, your view would be something like this:
<p>
<strong>Dob:</strong>
<%= #student.dob %>
<strong>Age:</strong>
<%= #student.age %>
</p>
I hope it helps
Quick fire question.
If I have a list of values and I wan't to find the total and display it in embedded ruby, how would I go about this.
<% #user.recipes.each do |i| %>
<% i.awards.each do |k| %>
<%= k.points %>
<% end %>
<% end %>
This renders:
1 10 5 5 10 1 5 10 5 1
with each number (1, 5 or 10) being a value from the database. Is there any way to get a count of this? Or would it be better to create a seperate method in the controller to work this out?
<%= i.awards.sum(:points) %>
For for the sum of all points from all recipes:
<%= #user.recipes.map { |r| r.awards.sum(:points) }.sum %>
Although it might be sensible to do this calculation within the model. You'll remove a lot of duplication that way if you use it in more than one view.
UPDATE:
As per the comments below, you could also ask the DB to calculate the sum for you:
<%= #user.recipes.joins(:awards).sum('awards.points') %>
I'm trying to loop through an array of the next 7 days, and for each, perform a query to find all the 'Time slots' that match, and add these to an object which I can loop through in my view. This is fairly simple in PHP, but I'm not sure of the syntax in rails. I have a situation where each day can have multiple 'delivery slots' available, and I need to display all these slots for the next week, by day.
So far in my controller I have
d = Date.today
d2 = d + 1.week
#days = (d..d2).to_a
#deliveries = []
#days.each do |d|
#deliveries[][dayname] = d.strftime("%a")
#deliveries[][slots] = Model.where("day = ?", d.strftime("%w"))
end
Then in my view, I want to do this
<% #deliveries.each do |d| %>
<%= d.dayname %>
<% d.slots.each do |s| %>
<%= slot data here %>
<% end %>
<% end %>
Where am I going wrong? Not quite sure of the syntax in rails where you'd use "as key => value" in php. Is this the most efficient way to go about it? It will result in 7 queries which isn't ideal
Thanks for any help
If your Model only has a day number, the slots will be the same for every week and you could do something like:
slots_by_day = Model.all.group_by(&:day)
#deliveries = (Date.today..Date.today + 6.days).each_with_object({}) do |day, dayname_groups|
dayname_groups.merge!(day.strftime('%a') => slots_by_day[day.strftime('%w').to_i])
end
It will fetch all models, group them by day number of the week and then build a hash mapping each day number with the day name ending up in a hash like:
=> {"Wed"=>[#<Model...>, #<Model...>, #<Model...>, #<Model...>],
"Thu"=>[#<Model...>, #<Model...>, #<Model...>, #<Model...>], "Fri"=>...}
The hash would be used like this:
<% #deliveries.each do |dayname, slots| %>
<%= dayname %>
<% slots.each do |s| %>
<%= slot data here %>
<% end %>
<% end %>
I am trying to get a loop to post videos grouped by each day by created_at.
For example:
December 5, 2012 -
Video 9
Video 8
Video 7
December 4, 2012 -
Video 6
Video 5
December 3, 2012 -
Video 4
Video 3
Video 2
Video 1
videos_controller:
def index
#title = 'Hip Hop Videos, Breaking News, Videos, And Funny Shxt | HOTDROPHIPHOP'
#description = ''
#videos = Video.all
#days = Video.where(:created_at == Time.today )
end
View file:
<% #days.each do |day| %>
<div class="video-date">December 4, 2012</div>
<% #videos.each do |video| %>
<% end %>
<% end %>
I also need to get that div to show that day's date as well.
I searched around and couldn't find a solution and tried the group_by (which seemed the cleanest) but couldn't get it to work. I am a bit rusty on my Rails as I haven't touched it for months.
You can do this:
#videos = Video.where(Video.arel_table[:created_at].gteq(some_date_value))
#video_days = #videos.group_by {|video| video.created_at.to_date }
Where #video_days will be a hash in the form of {some_date_value: [{video1}, {video2}, etc], next_date_value: [{video3}, {video4}, etc], etc...}.
Since you are calling .to_date on the created_at field, it will drop all of the time information, effectively grouping everything by day.
You can loop through it like:
<% #video_days.each do |day, videos| %>
<%= day.strftime("some format") %>
<% videos.each do |video| %>
<%= #output videos how you see fit %>
<% end %>
<% end %>
The best way is to use the gem Groupdate
e.g User.group_by_day(:created_at).count
Allow you to order by day, week, hour
First of all it makes no sense to call only videos from today and then run through all videos.
I would try it this way:
Controller
#videos = Video.all(:conditions => ["created_at >= ?", Date.today.at_beginning_of_month])
View
<% Date.today.at_beginning_of_month.upto(Date.today).each do |date| %>
<%= date %>: <%= #videos.select{|u| u.created_at == date }.title %>
<% end %>
It should give you a Video list with "Date: Video Title" for the actual month.
Assumed you are using mysql and video has attribute title
I am posting the following code to help you to grasp the logic ( Surely it need re-factoring )
Controller
#videos = {}
videos = Video.order("DATE(created_at) DESC, title ASC").select("DATE(created_at) as created_at, title, id" )
videos.collect{|x| #videos[x.created_at.to_s] = #videos[x.created_at.to_s] ? #videos[x.created_at.to_s] << x.title : [x.title] }
view
<% #videos.each do |posted_date, videos| %>
<div class="video-date"><%= Date.parse(posted_date.to_s).strftime("%b %d, %Y") %> </div>
<%= videos.join(", ") %>
<% end %>