I'm building a school calendar that lists classes ("sections") and displays semester and exam dates for those classes. The calendar is fed a hash that is defined in the Section.rb model:
def get_calendar
calendar = {}
calendar[:semesters] = Semester.where(section_id: self.id)
calendar[:exams] = Exam.where(section_id: self.id)
{ :calendar => calendar }
end
The Semester and Exam objects have a name, start_date and end_date.
When looping through each day of the calendar, how can I check if there's a semester or exam with a start_date or end_date for that day of the loop?
If there is a semester or exam with either a start_date or end_date that matches the calendar date, I would to display the name.
The calendar dates and the start_date and end_date fields all use the Date class (link).
I sincerely appreciate the help. I can clarify the question if needed :)
Thank you!
Maybe you should re-think your hash, and use it this way:
def get_calendar
semesters = self.semesters
exams = self.exams
events = { }
(semesters + exams).each do |event|
start_date = event.start_date.to_s
events[start_date] ||= []
events[start_date] << event
end_date = event.end_date.to_s
events[end_date] ||= []
events[end_date] << event
end
events
end
And test the presence of an event in the loop that constructs the Calendar:
dates_of_calendar.each do |date|
if #events[date.to_s].present?
# well, there is an event happening for this date! treat it as your wishes!
end
# etc...
end
Would the enumberable detect method work? http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-detect
So as your looping through your condition could be...
semesters.detect{|s| s.begin_date > cal_begin_date ... //more conditions here} &&
exams.detect{|e| e.begin_date > cal_begin_date ... //more conditions here}
Related
Im trying to gather all sales made within a week and put each sale in day made. If Moday was two sales, then Monday => {...}, {...} etc
"Monday" would be ruby's date format.
In my db I have 5 sale objects: Two sales on Monday and two on Tuesday.
Controller:
def daily_customer_sale(created)
date_and_id = Sale.where('created_at >= ?', created).pluck(:created_at, :id)
date_and_id.each do |obj|
yield(obj.first, obj.last)
end
end
def daily_sales(created=nil)
sales_by_date = Hash.new(0)
daily_customer_sale(created) do |date, id|
s_date = date.to_date
sales_by_date[s_date] = Sale.find(id) # Seems to return only one object per day
end
return sales_by_date
end
For views:
daily_sales(1.week.ago.to_datetime)
What I get in two dates (correct) in which each data has only one object when it should be two or more per date. Is there something wrong?
You don't need complex logic to do it. Here is a cleaner way
Sale.where('created_at >= ?', created_at).group_by{ |sale| sale.created_at.to_date}
It will return All the sales grouped by day.
key will be date object and for each day there will be sale array containing all of the sales for that day.
If you need string based key you can format it as you like as per below
Sale.where('created_at >= ?', created_at).group_by{ |sale| sale.created_at.to_date.to_s } #default date format
Sale.where('created_at >= ?', created_at).group_by{ |sale| sale.created_at.to_date.strftime("%d/%m/%Y") } #23/09/2016
You can have a look at Group by method
I am having a Quote model which consists of due_date and other fields.
I need to write a condition where we have to display all the records where due_date (which is date data type and stored in database as yyyy-mm-dd format) is less than current date.
For example, current_date is today's date, so I need to display all the records till yesterday.
I wrote a condition but didn't work, can you tell me where I went wrong?
def past_quotes
#items = []
current_date = Time.now.strftime("%Y-%m-%d")
daily_items = Quote.by_account(#account).active.includes(:company).where('due_date' < current_date)
#items << Item.new(items: daily_items) unless daily_items.empty?
end
But still displaying all the records, I think condition is wrong.
You shouldn't use a string when comparing the dates. ActiveRecord should be able to handle dates directly
daily_items = Quote.by_account(#account).active.includes(:company).where('due_date < ?', Date.today)
Can you try following query:
def past_quotes
#items = []
daily_items = Quote.by_account(#account).active.includes(:company).where('due_date < DATE(?)', Time.now)
#items << Item.new(items: daily_items) unless daily_items.empty?
end
I have a ressource Room that has_many reservations. Likewise the ressource Reservation belongs_to a room.
My reservation model has a starts_at and an ends_at attribute.
In my index action for the Room controller I want to get all the Rooms and include all the reservations for a certain date(the date is given as a parameter).
I have tried this code, but it doesn't seem to work as intended.
#rooms = Room.includes(:reservations).where("reservations.starts_at" => params[:date])
I am aware that this code does not take into account that a room could be reserved for multiple days, but I had to start somewhere.
SUM UP
Based on a date the action should return all the rooms, but only include the reservations that is relevant for that date.
EDIT
This is what I ended up doing.
controllers/rooms_controller.rb
def index
#rooms = Room.includes(:reservations)
#date = params[:date] ||= Date.today
end
views/rooms/index.html.haml
- #rooms.each do |room|
- room.reservations.relevant(#date).each do |reservation|
= reservation.id
models/reservation.rb
def self.relevant(date = Date.today)
if date.blank?
date = Date.today
end
where(
'(starts_at BETWEEN ? AND ?) OR (ends_at BETWEEN ? AND ?)',
date.to_date.beginning_of_day, date.to_date.end_of_day,
date.to_date.beginning_of_day, date.to_date.end_of_day
)
end
It works alright, but the view is talking to the model I think?
If your where conditions refer to another table then you also need to need to specify references as well as includes. e.g.
#rooms = Room.includes(:reservations).
where("reservations.starts_at" => params[:date]).
references(:reservations)
See the API documentation here.
I need to validate two dates in date time format that come from create new record form. Right now the form has drop downs for year, date, month, hour, minute. In the controller, I need to validate that the start date is not greater than end date and it will not let me compare it using the params[:start_date] > params[:end_date].
How can I properly validate that the start date is not larger than the end date when adding a new record to the database, I should be doing this in the model but I cannot figure out how you do it. Does anyone here has any examples I can look from?
Add custom validation to your model to verify that the start date is less than the end date. Something like this would work:
# app/models/my_model.rb
validate :dates_in_order
def dates_in_order
errors.add(:start_date, "must be before end time") unless start_date < end_date
end
#some_model.rb
before_create -> {
errors.add(:base, "Start date cannot be later than end date.") if start_date > end_date
}
Not what you're asking for, but may also be a way to handle this. People sometimes don't read the labels so closely.
before_create :confirm_dates_in_order
def confirm_dates_in_order
start_date, end_date = end_date, start_date if start_date > end_date
end
I have an event table that contains start_at and ends_at. It also have a boolean for allday.
If the event is allday, then the user enters a field called hours. But, if they enter the start_at and ends_at, I'ld like to calculate and save in the hours field.
In English (not Ruby):
If event.allday = > true
hours = ends_at - starts_at
This way, I wouldn't have to calculate it during all the different display pages I have and it would be easier to sum.
OR - would this logic go into the model?
Thanks!
UPDATE-----------
I tried putting this into the model:
before_save :calculate_hours
def calculate_hours
if self.allday != true
self.hours = ((self.ends_at - self.starts_at)/ 3600).to_f.round(2)
end
end
Business logic always belongs in the model.
class Event < ActiveRecord::Base
before_validation :set_hours
private
def set_hours
if allday?
self.hours = ends_at - starts_at
end
end
end