My Code works. The problem I have here is that dates like November 31 and April 31 can occur every year from 2010 down to 1995 which means I have to type in all these dates e.g [Date.new(2012,09,31),Date.new(2011,09,31)] and so on. I am trying to make this validation work for only the month and the day to avoid too much typing or in other words shorten my code please see a description of my
Model/profile.rb
validate :excluded_dates
private
def excluded_dates
exclusion_dates = [Date.new(2012,9,31), Date.new(2012,2,1)]
if exclusion_dates.include?(self.next_shoeing)
self.errors.add(:next_shoeing, "cannot be on a reserved date.")
end
First of all doing Date.new(2012,9,31) will throw you an ArgumentError: invalid date. IMO there is no need to validate this as no one will be able to construct such date (just handling this exception outside this model).
So if next_shoeing is an instance of Date it won't be invalid anyway.
Related
I have an error message that needs to be translated along with parameters. What is the best way to do it in rails?
dates = '12th June - 14th June'
errors.add(:base, :reserved_dates)
From en.yml
activemodel:
errors:
models:
reserve_changes:
reserved_dates: "Dates changes from %{dates}"
Expected output:
Dates changes from 12th June - 14th June
When running this way I only get Dates changes from without the passed parameters.
You need to pass in the dates as an option to the errors.add:
dates = '12th June - 14th June'
errors.add(:base, :reserved_dates, dates: dates)
Otherwise the translator has no access to the string you want to substitute.
I have an input for time, and I only want to accept a couple of input values (6am 7am 8am 9am 10am 11am 12pm ...).
In my model, I have tried:
VALID_TIMES = %w(6am 7am 8am 9am 10am 11am 12pm 1pm 2pm 3pm 4pm 5pm 6pm 7pm 8pm 9pm 10pm)
validates_inclusion_of :final_selected_time, :in => VALID_TIMES
but it isn't working. I have also tried other methods according to the rails form validation documentation, but none of them seem to work with strings. They only work with numbers.
Does anyone know a way to validate a param like :final_selected_time for string values?
Update:
The above code should work to validate strings.
You should provide us with more information. We cant help you without it. What does object actually get? Your code is ok since you changed column type to string. It checks if value equals to one of strings you specified.
Anyway you can always make the validation yourself without rails DSL (almost):
validate :final_selected_time_should_be_NICE
private
def final_selected_time_should_be_NICE
return if final_selected_time ... # is ok
errors.add(:final_selected_time, :not_appropriate)
end
Just change method name so it will correspond to your business logic and add condition.
On rubular I tested and confirmed that this does a good job confirming the desired format of a date entry:
\A\d\d\/\d\d\/\d\d\d\d\z
Tests:
01/02/2000 #pass
11/21/2014 #pass
11-21-2014 #fail
A3-21-2014 #fail
I want to make it a little bit better, and it will be good enough for me. What I want is to confirm that the "month field" (the first two digits) is anywhere from 01 - 12, where each single digit is led by a zero. (Ex: 01,02,03 etc as opposed to: 1,2,3).
Next: I want to do the same thing for the next two digits to confirm that the next two digits (the day field) is between 01 - 31. Same thing: Each single digit needs to lead with a zero.
Tests:
01/02/2017 #pass
12/31/2017 #pass
1/02/2017 #fail
01/2/2017 #fail
50/01/2017 #fail
01/50/2017 #fail
I realize that this regex will be inaccurate for those months that have fewer than 31 days, but it is good enough for what I am doing.
Well this should get you most of the way there:
/((02\/[0-2]\d)|((01|[0][3-9]|[1][0-2])\/(31|30|[0-2]\d)))\/[12]\d{3}/
Granted it does not handle the following:
Leap Years e.g. 02/29 is acceptable regardless of the year
All Years from 1000-2999 are acceptable
Months with only 30 days e.g. 09/31 is acceptable
Small Breakdown in case links break:
Here is the runout on Rubular
Here is an explanation from Regex101
(02\/[0-2]\d) - Starts with 02/ then allow 0-2 followed by 0-9
OR ((01|[0][3-9]|[1][0-2]\/(31|30|[0-2]\d)) - Starts with (01 or 0 followed by 3-9 or 1 followed by 0-2) followed a / followed by 31 or 30 or 0-2 followed by 0-9
In both cases must be followed by 1 or 2 followed by 3 digits 0-9
Really wish ruby supported look behind conditionals like true pcre Example for edification
As a Note: as mentioned in the comments rescuing a parsing failure is probably easier than using a regex but I figured since you asked.
What I did was used the american_date gem. On your date inputs: the user should enter the date in the format of: "mm/dd/yyyy".
In order to force the user to enter the date in this format: I used jquery-inputmask-rails. I defined my mask like so:
$('.mask_american_date').inputmask({mask: "99/99/9999"});
Now there will be a nice mask on the date input that looks like this:
__/__/____
Now: all you need is a presence validator for the date field in your model:
validates_presence_of :date_of_birth, message: "Date is either invalid or is not present".
And this covers everything. How american date works is it takes the user input and attempts to convert it into a date. If it cannot convert the user input into a date for any reason: it will return nil which triggers the above validation.
This includes a bad month entry or a bad day entry. American Date is smart enough to know, for example, that September only has 30 days in it. So: if the user enters "31" for the day section, ex: 09/31/2017, american date will convert the date to nil.
This question already has answers here:
How do I validate a date in rails?
(10 answers)
Closed 7 years ago.
Okay so September has 30 days right.
This is what rails does when you set an invalid date like 31 September:
s = Student.first
s.date_of_birth = "2015-09-31"
s.save!
> true
s.date_of_birth
> Thu, 01 Oct 2015 00:00:00 UTC +00:00
It sets the date to 1st of October.
What I want is something like this
s.save!
(0.4ms) BEGIN
(0.5ms) ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: Date is not a valid date
Is there no way to force Rails to explicitly error out when setting such a crap date? The standard rails date_select does not dynamically change the number of days in the days dropdown when you change to a different month. So you can select 31 September with the dropdowns, and the date will be saved as 1st of October. But I want to display an error message.
I don't want people to accidentally put the wrong dates into my system.
I think one of the solutions would be to change the datatype of date_of_birth from datetime to date. This way Rails would validate the date and would not allow the situation, you've shown.
It is also a good practice to store dates in date type, because it leads to significant decrease in potential issues, when working with those dates.
Try adding this to your model:
def date_of_birth=(d)
date = Date.strptime(d.to_s)
send(:write_attribute, :date_of_birth, date)
end
Now if you try setting an invalid date, it should raise an exception:
s.date_of_birth = "2015-09-31" # raises an exception
However, I don't think that doing this is a good idea. It's probably a better idea to do as Andrey Deineko said and store it in a date type.
I am using postrges db.
My domain has a date field:
java.util.Date requestedDate;
I am trying to search by date in my controller:
eq ("requestedDate", requestedDate)
This works fine, but the problem is that date and time has to be exactly matching for this. But in application the user will only enter the date to search items (like give me all requests which are made on 2014-02-05 and the browser application will add the current time to the request). So the comparison fails because the user entered time is different from the time during creation of the request.
I tried 'like' but it throws error.
How to compare only date part ?
You could do something like this:
Date now = new Date()
now.clearTime()
def results = Meeting.withCriteria {
between('date', now, now+1)
}
So this strips off the time portion of the current date, and then does a 'between' query (between midnight just gone and midnight 24 hours later).
Still it looks like there is no convenient way to realize this.
You need a small detour by computing the start of the day and the end of the day and use the between operator.
EDIT
I just saw now rcgeorge23 gave you the right example for doing this.