Scope date until date+week - ruby-on-rails

I want get all my records which have a start_date(So not the normal creation_date) from my stringed date(11-20-2013) within a scope of 1 week.
I've never really used scoping in Rails before so I'm rather lost here. Should I use a .where()? If so, How do I adress start_date+1 week in this scope?
I've tried something like:
if params[:startdate]
group = Group.find_by_id(params[:group_id]).where(:start_date => params[:startdate]..params[:startdate] + 1.weeks)
end
Which throws: can't convert ActiveSupport::Duration into String

Because params[:startdate] is String when you need DateTime.
You can try to parse it
startdate = DateTime.parse(params[:startdate]) rescue nil
if startdate
group = Group.find_by_id(params[:group_id]).where(:start_date => startdate..startdate + 1.weeks)
else
# you get wrong startdate
end

Related

How to test specific dates that cannot be parsed

I need to test a specific array of dates to ensure that they are in the correct format, however I cannot use 'parse' because, if I do, the dates that are incorrect are sorted out. For instance, if I have an incorrect date with a month "13", it adds another year and sets the month to 1.
My code pulls in the dates from an SQL query:
table_birth_dates = self.class.connection.execute("SELECT birth_date FROM #{temp_table_name}").values.flatten
[
[0] "1980-30-54",
[1] "1980-30-54",
[2] "2020-09-10",
[3] "1890-10-30"
]
yr = 1900
year_test = table_birth_dates.select{|d| Date.parse(d).year < yr}
This now gives me an ArgumentError: invalid date.
I thought of using:
splitted_birth_date = table_birth_dates.first.split("-")
splitted_birth_date.first.to_i > 1900?
but if I try to loop through all of my dates, I'm not able to manipulate anything via splitting:
table_birth_dates.each do |birth_date|
birth_date.split("-")
end
What can I do with this?
I need to test a specific array of dates to ensure that they are in
the correct format...
If you get an error it means that the date is incorrect, you could rescue that error and do anything you want with that date to make it valid or whatever.
table_birth_dates.each do |birth_date|
begin
if Date.parse(d).year < yr
# do smth
end
rescue ArgumentError => e
# do smth with `d`
end
end
You could combine your select and split approaches together:
table_birth_dates.select { |d| d.split('-').first.to_i < 1900 }
#=> ["1890-10-30"]

Rails date check if parsable

I have a datetime picker which sends the checkin & checkout dates with search box. Then the url looks like;
http://localhost:3000/locations/listings?utf8=%E2%9C%93&search=london&start_date=12%2F04%2F16&end_date=20%2F04%2F16
and I take the params hash and parse the string,
start_date = Date.parse(params[:start_date])
end_date = Date.parse(params[:end_date])
first of all, I have to check if (start_date.present? && end_date.present?) and that works fine.
But if the user manually types something else rather than the date to url such as;
http://localhost:3000/locations/listings?utf8=%E2%9C%93&search=london&start_date=londoneye6&end_date=20%2F04%2F16
Then of course I get an error;
invalid date
How should I control if the string is parsable on controller action. I should be also checking london-eye, london/eye strings, which include - /
Thank you
You have to try parsing the string and rescue ArgumentError
begin
myDate = Date.parse("31-01-2016")
rescue ArgumentError
# handle invalid date
end
one line (please note that this rescues all errors)
myDate = Date.parse("31-01-2016") rescue nil
You can validate time with Date.parse, and just trap ArgumentError exception on parse returning nil out:
controller:
def param_date date
Date.parse(date)
rescue ArgumentError
nil
end
start_date = param_date(params[:start_date])
end_date = param_date(params[:end_date])

RoR compare timestamp symbol to Time.now date in controller

I'm trying to do something like this in my controller:
#inventory_items = #store.inventory_items.where(:updated_at < Time.now - 1.minute)
I keep getting a comparison of Symbol with Time failed error.
I tried to call to_datetime and to_date on :updated_at, but perhaps those only work on strings or integers?
How can I get :updated_at into a proper date format to compare with Time.now - 1.minute?
Thanks in advance!
Well, there are some ways you can do it.
The reason it doesn't work is because the symbol is only a pointer to the column and not the column itself.
So, either you do
#inventory_items = #store.inventory_items.where(["updated_at < ?", Time.now - 1.minute])
or as an alternative
#inventory_items = #store.inventory_items.where(["updated_at < :one_minute_ago", {one_minute_ago: Time.now - 1.minute]})
Or, you could do
#inventory_items = #store.inventory_items.where.not(:updated_at => Time.now - 1.minute..Time.now)
I do not think with the hash style you can use less than or greater than checks. Try the following:
#inventory_items = #store.inventory_items.where('inventory_items.updated_at < ?', Time.now - 1.minute)
As far as "proper date format" is concerned, you need not worry about them here. All database dates are by default converted to UTC.

ActiveRecord where method call optimisation

I have a piece of code witch looks like this:
Post.all.reject {|p| p.created_at.beginning_of_month != params[:date].to_date}
Is there a method to write the same code using where method and to not get all elements?
If you want to use where, I'd go by:
# x-month being a date from your desired month.
# .. defines the range between the beginning and the end
Post.where(:created_at => x-month.beginning_of_month..x-month.end_of_month)
AFAIK, there is no database-agnostic solution to this, because you need to extract the month from the date. So, in raw SQL you would have :
date = params[:date].to_date
Post.where("MONTH(created_at) != ? AND YEAR(created_at) = ?", [date.month, date.year])
Now it is possible to cheat a bit with normalization in order to use a db-agnostic solution.
Just add some created_at_month and created_at_year columns to your model, along with this callback :
after_create :denormalize_created_at
def denormalize_created_at
assign_attributes created_at_month: created_at.month,
created_at_year: created_at.year
save validate: false
end
Now you can do:
Rails < 4 :
date = params[:date].to_date
Post
.where(Post.arel_table[:created_at_month].not_eq date.month)
.where(created_at_year: date.year)
Rails 4+ :
date = params[:date].to_date
Post.not(created_at_month: date.month).where(created_at_year: date.year)
mysql has a MONTH function to get the month of a datetime column.
Post.where("MONTH(created_at) != ?", params[:date].to_date.month)

Thinking Sphinx with a date range

I am implementing a full text search API for my rails apps, and so far have been having great success with Thinking Sphinx.
I now want to implement a date range search, and keep getting the "bad value for range" error.
Here is a snippet of the controller code, and i'm a bit stuck on what to do next.
#search_options = { :page => params[:page], :per_page => params[:per_page]||50 }
unless params[:since].blank?
# make sure date is in specified format - YYYY-MM-DD
d = nil
begin
d = DateTime.strptime(params[:since], '%Y-%m-%d')
rescue
raise ArgumentError, "Value for since parameter is not a valid date - please use format YYYY-MM-DD"
end
#search_options.merge!(:with => {:post_date => d..Time.now.utc})
end
logger.info #search_options
#posts = Post.search(params[:q], #search_options)
When I have a look at the log, I am seeing this bit which seems to imply the date hasn't been converted into the same time format as the Time.now.utc.
withpost_date2010-05-25T00:00:00+00:00..Tue Jun 01 17:45:13 UTC 2010
Any ideas? Basically I am trying to have the API request pass in a "since" date to see all posts after a certain date. I am specifying that the date should be in the YYYY-MM-DD format.
Thanks for your help.
Chris
EDIT: I just changed the date parameters merge statement to this
#search_options.merge!(:with => {:post_date => d.to_date..DateTime.now})
and now I get this error
undefined method `to_i' for Tue, 25 May 2010:Date
So obviously there is something still not setup right...
lets say d = "2010-12-10"
:post_date => (d.to_time.to_i..Time.now.to_i) would have gotten you there. I just did this in my project and it works great
I finally solved this, but it takes a slightly different approach but it works fine.
I was trying to put the date-range search inside a sphinx_scope (in the model) or as a :condition or :with (in the controller). This did not work, so instead I had to implement it inside the define_index in the model.
So what I did was put a check in the define_index to see if a record fell within a date range, the date range being defined by some SQL code, as shown below. In this case, I wanted to see if "start_date" fell within a date between now and 30 days ago, and an "end_date" fell within today and 30 days from now.
If the dates fell within the ranges, the code below causes the :live to be 0 or 1, depending on whether it falls outside or inside the date ranges (respectively):
define index do
# fields:
...
# attributes:
has "CASE WHEN start_date > DATE_ADD(NOW(), INTERVAL -30 DAY) AND end_date < DATE_ADD(NOW(), INTERVAL 30 DAY) THEN 1 ELSE 0 END", :type => :integer, :as => :live
...
# delta:
...
end
Then in your controller, all you have to do is check if :live => 1 to obtain all records that have start_dates and end_dates within the date ranges.
I used a sphinx_scope like this:
sphinx_scope(:live) {
{ :with => { :live => 1 } }
}
and then in my controller:
#models = Model.live.search(...)
To make sure it works well, you of course need to implement frequent reindexing to make sure the index is up to date, i.e. the correct records are :live => 1 or 0!
Anyway, this is probably a bit late for you now, but I implemented it and it works like a charm!!!
Wouldn't it work if you replaced
d = DateTime.strptime(params[:since], '%Y-%m-%d')
by
Time.parse(params[:since]).strftime("%Y-%m-%d")
(It seems the first one doesn't return a date in the expected format)

Resources