Comparing Time.now with model dates - ruby-on-rails

my Project model has 2 datetime atttributes: start_date and end_date.
Now I want all projects where the current time is in between these dates.
I tried something like this with the start_date to start with:
#projects = Project.where(:start_date <= Time.now)
But this returns an error:
comparison of Symbol with Time failed
Any ideas? Thanks!

Unlike some ORMs, active record doesn't augment the symbol class with methods to allow expressions other than equality to be expressed in this way. You just have to do
Project.where('start_date <= ?', Time.now)
The squeal gem adds this sort of stuff and allows you to write
Project.where{start_date < Time.now}

You can't do this: :start_date <= Time.now. You're comparing a symbol and a date with the <= operator.
If you want to add a condition to your query, pass it as a string:
Project.where("start_date <= ?", Time.now);

Unfortunately, with a where clause comparing dates, you'll have to drop into SQL. Try something like this instead:
#projects = Project.where(['projects.start_date <= ?', Time.now])

Related

How do I mix comparison operators with a joins query in Rails?

I want to do something like this:
Aoy.joins(:member).where(season_year: session[:season_year], members: {"debut_date.year <= ?", session[:season_year]} ).order(total_points: :desc).each_with_index do |aoy, i|
"Only show Aoy entries of members that have debuted in the same year or previous to the season_year session"
How do I mix comparisons and with join statement?
How do I extract "year" from debut_date (debut_date.year) within the .where statement, is that possible?
thanks
You need to write the query in SQL instead of ActiveRecord for handling this use case. For extracting year from a date field, you can use SQL YEAR method:
Aoy.joins(:member)
.where(season_year: session[:season_year])
.where("YEAR(members.debut_date) <= ?", session[:season_year])
.order(total_points: :desc)
You can use YEAR() of SQL ref
Aoy.joins(:members)
.where(season_year: session[:season_year])
.where("YEAR(debut_date) <= ?", session[:season_year])
.order(total_points: :desc)

Search records between two dates - Ruby on Rails

I am trying to create a search that returns records between two dates (today and a future date).
I can get it to return several records no problem if I use the following code in my model (film.rb):
def self.date_search(search_string)
self.where("release_date >= ?", search_string )
However, when I try something like the following, I receive syntax errors:
def self.date_search(search_string)
date = Date.today
self.where("release_date = created_at > date.strftime("%F") AND created_at < ? ", search_string )
I am still very new to Ruby so any help sorting out my syntax and code would be much appreciated.
Try:
def self.date_search(search_string)
self.where({release_date: Time.now..search_string})
end
This will give you entries where release_date is between the current time and the search_string (inclusive of the search string since you use two dots(..), it would be exclusive of the search string if you used three dots (...)

Rails query: Compare calculation of two attribute values

I have a model, Product, which has both a :created_at timestamp and an :expiration_in_days attribute. Products are considered expired a certain number of days after their creation. How do I write a query that only returns products that have not expired?
Rails 4, Ruby 2.1, PG 0.17
I have been trying queries like this, with no success:
#product.rb
def self.not_expired
where('created_at + expiration_in_days * 86400 >= ?', Time.now)
end
I have a pure Ruby version that works fine, it's just slower:
#product.rb
def self.not_expired
select{ |p| (p.created_at.to_i + p.expiration_in_days * 86400) >= Time.now.to_i}
end
note, the 86400 calculation converts the the :expiration_in_days integer into seconds
Any pointers on more advanced Rails queries than the documentation (http://guides.rubyonrails.org/active_record_querying.html) would be very welcome as well.
Thanks in advance.
Try this:
def self.not_expired
where("created_at + (expiration_in_days * 86400)::text::interval >= ?", Time.now)
end
UPDATE: Add references
You can learn more about date and time function here.
Given your case has a special requirement, which is the value of expiration_in_days is a column in the table, we cannot use created_at + interval expiration_in_days day. Instead, we need to type cast its value to interval. But you can't type cast straight to an integer, that's why we cast it to text first.
A + B > C is true if A <= C - B
So, instead of trying to add the expiration time to created_at, subtract the expiration time from Time.now.
def expiration_threshold
Time.now - amount_of_time # I'm not sure what type to use
end
def self.not_expired
where( "created_at > ? ", expiration_threshold )
end
I've always been a little stumped about what type Rails/Ruby will want when dealing with various dates/times, you may have to play around.
I'm not sure if this would work but try something like this
def self.not_expired
where("TIMESTAMP created_at + INTERVAL '1 day' * expiration_in_days >= NOW()")
end

Finding records between date range

I'm trying to find records whose start and end date range over a particular date. Date is random and :start_date and :end_date are attributes of the prices entity.
date = Time.now
record_i_want = Price.where(date => :start_date .. :end_date)
Thank you.
You can simply do
Price.where(:date => start_date..end_date)
This will result in the following SQL( for start and end dates - '2014-03-27', '2014-03-28')
SELECT `prices`.* FROM `prices` WHERE (`prices`.`date` BETWEEN '2014-03-27' AND '2014-03-28')
EDIT:
Realized that this is the query you are looking for. Thanks, Coenwulf for pointing it out
Price.where(['start_date < ? AND end_date > ?', date, date])
You want to select rows where your date is greater than the start_date and less than the end_date. You can specify the appropriate SQL where clause parameterized in your call to where like so:
Price.where([":date >= start_date AND :date <= end_date", {date: Date.today})
That will give you all the prices that match. If you know you'll get only one you can get it by calling first.
Price.where([":date >= start_date AND :date <= end_date", {date: Date.today}).first
Make any appropriate adjustment to the >= and <= if you want to exclude the start_date and/or the end_date from the results. If for example the Price is valid starting on the start_date but isn't valid through the end_date you can change the clause to:
":date >= start_date AND :date < end_date"
This should work:
def get_record_by_date(date)
Price.where([start_date.to_i < date.to_i] && [end_date.to_i > date.to_i])
end

Get records where date.year == some_year in Rails

I have a date column in my database in a Rails 3.1 app, and I want to be able to get the records where the date's year matches a specific year.
I tried where(:date.year == year) but of course I got NoMethodError: undefined method 'year' for :date:Symbol. Is it possible to do this type of query?
You can use a scope to build something like:
scope :for_year, lambda {|date| where("date >= ? and date <= ?", "#{date.year}0101", "#{date.year}1231")}
In your Model:
scope :by_year, lambda { |year| where('extract(year from created_at) = ?', year) }
In your Controller:
#courses = Course.by_year(params[:year])
Jesse gave you, I think, the idea for the actual solution, but to explain why this failed - it's because it tried to evaluate ".year" as a method on the symbol you passed it: ":date".
The word :date is just a parameter to tell "where" which value it will later use to construct the SQL query to pass to the db.
It doesn't turn into the actual date of the record. But the ".year" will evaluate as you're passing it as a parameter, before anything has been done with the ":date" symbol.
Assuming your date format is: YYYY-MM-DD HH:MM:SS
Try this:
where(Date.strptime(:date, "%Y-%m-%d %H:%M:%S").year == year)
OR
where(["YEAR(?) = ?", :date, year])

Resources