Rails where based on association - ruby-on-rails

I'm trying to query items based on an association but getting a bit confused with how to phrase the date part of my query. The dates are stored in text format like "2018-12-25".
year = params[:ridden_in]
#items = Item.joins(:cycle).where(cycles: { (:date.to_date).year: year })
Anyone able to help out where i'm going wrong?

The easiest way to do this is to use SQL functions. You could try to hide the SQL behind AREL but that very quickly becomes an incomprehensible mess.
One way would be straight string manipulation:
Item.joins(:cycle).where('substring(cycles."date" from 1 for 4) = ?', year)
or slightly more future-proof since your date will eventually become a real date:
Item.joins(:cycle).where('extract(year from cycles."date"::date) = ?', year)
Item.joins(:cycle).where('extract(year from cast(cycles."date" as date)) = ?', year)
Both of those assume that your date columns really do follow the ISO8601 date format.
If you're doing this a lot then you could add a partial index on cycles.date (i.e. index the result of whichever function you end up using).

Related

Rails - Check if a date belongs to a certain month in where query

Using Rails 6.
I have an ElectricityUsage model, with a Date field, date. I want to extract all the values for amount only for the current month. How would I accomplish this?
What I immediately attempted was the following:
ElectricityUsage.where(habitat: current_user.reservations[0].room.habitat).where(date.month: Date.today.month)
But that obviously doesn't work, and it wouldn't even account for the year, either. My DB is running on PostgreSQL, if that makes a difference.
You can use where with Date.current.all_month, which basically is just translated into a query using BETWEEN where the start date is the first day of the month and end date is the last one:
ElectricityUsage.where(habitat: current_user.reservations[0].room.habitat, date: Date.current.all_month)
This should work for you
ElectricityUsage.where(habitat: current_user.reservations[0].room.habitat).where("EXTRACT(MONTH FROM date) = ?", Date.current.month)
PostgreSQL Date/Time Functions and Operators
Might be a delayed response but you can use date_queries gem
model ElectricityUsage < ActiveRecord::Base
date_queries_for :date
end
Then you can simply use ElectricityUsage.dates_in_this_month to find all the records that false in current month

Rails ActiveRecord - Select all objects by date, using only day, month, year, but ignoring the rest of the date's components

I have a model named Event. I want to be able to get all Events that were created at some specific date which should be something like this
Event.where(created_at: "20/01/2019".to_date)
The issue is that the created_at field also contains minutes, second, etc, which I want to ignore. I only want to compare the date by day, month and year. Is there any way I can acchieve that?
You can use Date#beginning_of_day and Date.end_of_day both provided by ActiveSupport core extensions.
d = '2019-01-20'.to_date
Event.where(created_at:(d.beginning_of_day..d.end_of_day))
This will not necessarily compare "...the date by day, month and year." but instead it will create a between clause that encompasses the entire day. If you want to use the Hash finder syntax this is probably the best way to go about it.
You could go with
Event.where(
Arel::Nodes::NamedFunction.new('CAST',
[Event.arel_table[:created_at].as('DATE')]
).eq(d)
)
If you really only want to compare the day, month and year.
Option 1 will result in
events.created_at BETWEEN '2019-01-20 00:00:00' AND '2019-01-20 23:59:59'
Option 2 will result in
CAST(events.created_at AS DATE) = '2019-01-20'

Rails where statement with datetime.month

I am trying to find the data points within a database (PG) whose date is within a certain month (and would also quite like to check the year is the same also)
I have tried:
my_data.where("date.month = ?", month )
where 'month' is an integer (eg from Time.new.month) but doesn't seem to work...
So the query will be like this:
my_data.where("EXTRACT(MONTH FROM date) = ?", month)

Comparing datetime and date in a .where() on Rails

I'm working on an event system where admins can select events to feature and add promotional text. As they need to add additional text the featured events are in their own table and reference the event details.
I'm now trying to output featured events for each day in the next week. Simplified example:
day = DateTime.now.to_date
featured_events = #featured_events.where('event.start_datetime = ?', day)
The problem is that start_datetime is in datetime format and day is in date format so it always outputs nothing. Is it possible to compare these two values with .where()?
Thanks!
May be you're looking for this:
#featured_events.where('event.start_datetime > ? and event.start_datetime < ?', DateTime.now, 1.day.from_now.beginning_of_day)
You don't say what database you're using.
In PostgreSQL we'd truncate the datetime inside the DB query so the DBM can do the compare. On MySQL we'd use a function to convert the datetime to a date.

Querying a datetime range while taking into account the time zone

I'm having a lot of trouble with a query. I don't really know how to explain this well, but I'm going to try.
Basically, we have several objects with a 'posted_at' field that keeps the date and time something was posted, with the time zone, in a datetime field. I need to query and get a range by date with those objects.
Previously, I was converting that to Date and comparing it to another Date object. The query was something like this:
Date(posted_at) >= :start_date AND Date(posted_at) <= :end_date
However, when Postgre converted it to Date, it lost the timezone info which caused innacurate results to the query.
So, I changed to this:
if start_date then
start_time = Time.zone.parse("#{start_date.year}-#{start_date.month}-#{start_date.day}")
conditions << "posted_at >= :start"
hash[:start] = start_time
end
if end_date then
end_time = Time.zone.parse("#{end_date.year}-#{end_date.month}-#{end_date.day}").end_of_day
conditions << "posted_at <= :end"
hash[:end] = end_time
end
While this gets me the accurate results, it also has horrible performance and is causing some timeouts in my application.
I couldn't find any other way to do this query and still keep the accurate results. Would anyone have some advice or ideas?
Thank you in advance.
You never want to store timezone information in your database.
Here's a read that discusses some of the pitfalls:
http://derickrethans.nl/storing-date-time-in-database.html
You'll get better results as tadman suggests: add a new field with your timestamp at time zone 'utc', and index it. You'll then be able to grab stuff using posted_at between ? and ?.
You may have more luck converting your start and end times to UTC which would render the time-zone mostly irrelevant when making the query itself. This is done easily enough:
start_date.to_time.to_datetime.beginning_of_day.utc
end_date.to_time.to_datetime.end_of_day.utc
You can also adjust your query to be:
posted_at BETWEEN :start AND :end
Be sure to have an index on the fields you're searching, too, or you will get horrible performance.

Resources