ActiveRecord where method datetime passed - ruby-on-rails

Thanks for your continuing support in my latest venture in a Rails app. It's been a while since I've made something in Rails so here is my latest question. I appreciate the help you've all given in the past.
I have a Model called Event.rb which contains a date:date and time:time fields for the Event.
I also have a method inside of the model which is..
def begins
DateTime.new(date.year, date.month, date.day, time.hour, time.min, time.sec)
end
As I can't see if something has truly passed because I only have Date and Time separate so I need them together.
My question is...
I want to be able to add in the DateTime :begins into the following other method in my Model...
def self.past
where("date <= ?", TIME_NOW)
end
Just like I have a method which is...
def upcoming?
self.date >= Time.now
end
Which I could easily change self.date to begins and would past I would imagine?
Thanks!

Perhaps something like this will work for querying the database for past events using your existing date and time columns:
scope :past, lambda {
where("date <= ? and time <= ?",
Time.now.strftime("%Y-%d-%m"),
Time.now.strftime("%H:%M:%S")
)
}
past_events = Event.past
For checking the current instance, you could continue to use your begins method:
def past?
begins < DateTime.now
end
#event = Event.first
#event.past?

Related

Rails 4: Sorting by 2 different scopes/class methods

I'm trying to sort my events by future events then by events that have already ended. I tried using 2 different scopes but I'm thinking now that I might need to use class methods instead. I'm just struggling on how, syntactically, I need to write these methods.
event.rb:
def active
self.event_date > Time.now
end
def inactive
self.event_date < Time.now
end
"event_date" is a datetime column in the events table.
events_controller.rb:
def index
#events = Event.all.sort_by {|a,b| [a.active, b.inactive]}
end
With this code, I'm getting an error: "undefined method `inactive' for nil:NilClass" but I've tried it several different ways and can't seem to figure out how to write it.
Your methods will be executed after running through the database and will be slow.
This can probably be improved:
Model
scope :active, -> { where('event_date >= ?', Time.now) }
scope :inactive, -> { where('event_date < ?', Time.now) }
Controller
#active_events = Event.active
#inactive_events = Event.inactive
#events = #active_events + #inactive_events

Fetching Data based date and time

I am trying to find results from today onwards but also want to include the yesterdays plans if the time is between 12:00am-5:00am
Right now i have the following
def self.current
where(
"plan_date >= :today",
today: Date.current,
)
end
Is there a way i can know the time of the day based on the users timezone which am setting as bellow in the app controller and make sure that if its before 6:am the next day i want to include the previous days results as well.
def set_time_zone(&block)
if current_user
Time.use_zone(current_user.time_zone_name, &block)
else
yield
end
end
Try this:
def self.current
where(
"plan_date >= :today",
today: (Time.zone.now.in_time_zone(get_user_time_zone) - 6.hours).beginning_of_day,
)
end
...where get_user_time_zone returns the time zone for the user (E.G.: America/New_York). I'm using - 6.hours because you wanted it to be "before 6am" local time.

how to filter display based on date in Rails (easy)

def home
#guide = Guide.all
#finished = Guide.where(:date_starting <= Time.now)
end
Why doesn't this work? In my controller I want to compare the the start date of the objects in my database with the Time now, so that Exhibitions that are no longer on display are in the '#finished' variable. I get the error 'comparison of Symbol with Time failed'.
Thanks
Because the where() method does not do comparisons like you show here.
Your query could be written like so:
Guide.where('date_starting <= ?', Time.now)
or
Guide.where('date_starting <= :now', {now: Time.now})

updating a model attribute that will only change once

I have a subject model with attributes including a start_date and end_date - as well as a completed boolean attribute.
In subject.rb, I have a method to find how many weeks are remaining for a given subject:
def weeks_left
time = (self.end_date.to_time - Date.today.to_time).round/1.week
if time < 0
"completed"
elsif time < 1
"less than 1 week"
elsif time == 1
"1 week"
else
"#{time} weeks"
end
end
I want to tick the completed attribute if self.weeks_left == "completed" and the best way to do that seems like a call back, but I'm a bit unsure about using after_find - in general it seems like it would be too many queries, and indeed too big of a pain (especially after reading this) - but in this case, once a subject is complete, it's not going to change, so it seems useless to check it's status more than once - what's the best way to handle this?
Why dont you make a scope for this?
scope :completed, ->{where("end_date <= ?", Time.now)}
and a method
def completed?
self.weeks_left == "completed"
end
Looks like you need ActiveRecord::Callbacks. You can see more information here or on rails guide
before_save :update_completed
def update_completed
if (end_date_changed?)
time = (self.end_date.to_time - Date.today.to_time).round/1.week
self.complete = time < 0
end
end
This way you update the complete flag whenever end_date changes and it would always be in sync.
However because this is a calculated value you could also not store it as an attribute and simply define a method to get it
def complete
time = (self.end_date.to_time - Date.today.to_time).round/1.week
return time < 0
end

Sum / grouping with date constraints?

i've written the following sum/group methods in my 'StatementSales' model and want to be able to constrain the results by date, at the moment it's just producing totals for all valid db entries. In my views I want to provide links to 'One Week, One Month, Three Months, One Year' etc and ideally pass these to the methods below. How should I approach this?
def self.total_units
sum(:units)
end
def self.units_by_store
group(:store).sum(:units)
end
def self.units_by_territory
group(:territory).sum(:units)
end
def self.units_by_upc
group(:upc).sum(:units)
end
Many thanks in advance!
You could use scopes
Add this to your class
scope :between_dates, lambda { |start_date, end_date| where("date < #{end_date} AND date >= #{start_date}") }
scope :one_week, between_dates(Date.today, Date.today + 7.days)
Then you can do
def self.total_units
self.one_week.sum(:units)
end

Resources