Formatting the way a string is entered into my database
I am wanting to format data entered into a string column (confusingly named time
) of my database in a certain way. Because of legac开发者_Python百科y data issues on this project I can't simply change the column type from string to time because I would lose the old entries.
I simply want to require that the format of the information entered into the form and then submitted to the database is as follows:
00:00 where a 0 can by any integer 0-9.
How would I do that within a form_for
.
I am using Rails 2.3.8.
A work around that might help:
First create a migration doing:
rename_column :the_models, :time, :old_time
add_column :the_models, :time, :time
So now, the model will have a field called old_time
containing the original time data, and a new time
field having the correct field type.
As a result, the existing forms would seems like lost all the time data, but at least they are calling the_model.time
to get the result.
The real work around part:
class TheModel < ActiveRecord::Base
def time
read_attribute(:time) || Time.parse(read_attribute(:old_time))
end
end
So now the time value will be saved into the time
filed.
When time
is nil, it will try to get the time value from the old_time
and convert it to a time object.
There are two drawbacks:
- Time.parse("12:34") would give you something like:
2010-12-14 12:34:00 +0800
Because you gave it only the hr and min, other fields are not reliable. - You have a nearly deprecated field called
old_time
in the database. So in the future, you may want to completely remove that field, after you have confidence that allold_time
values has been converted to thetime
field.
One more note:
You should convert existing forms, for :time
field which probably using text_field.
The text_field may become showing something like 2010-12-14 12:34:00 +0800
.
If you really still want to use text_field, you could:
def time
t = read_attribute(:time)
t.nil? ? read_attribute(:old_time) : t.strftime("%H:%M")
end
def time=(val)
write_attribute(:time, Time.parse(val))
end
Your regex would be:
/[0-9]{2}:[0-9]{2}/
or
/\d\d:\d\d/
Here are some tests:
'00:00'[/[0-9]{2}:[0-9]{2}/] # => "00:00"
'12:00'[/\d\d:\d\d/] # => "12:00"
'11:59'[/[0-9]{2}:[0-9]{2}/] # => "11:59"
'23:59'[/\d\d:\d\d/] # => "23:59"
':'[/[0-9]{2}:[0-9]{2}/] # => nil
':0'[/[0-9]{2}:[0-9]{2}/] # => nil
'0:0'[/[0-9]{2}:[0-9]{2}/] # => nil
'000:0'[/[0-9]{2}:[0-9]{2}/] # => nil
'0:000'[/[0-9]{2}:[0-9]{2}/] # => nil
Up to this point I was working with your specified solution, but here's where it breaks down:
# BUG?
'1:00'[/[0-9]{2}:[0-9]{2}/] # => nil
# Fix?
'1:00'[/[0-9]{1,2}:[0-9]{2}/] # => "1:00"
# *** BUG ***
'99:99'[/[0-9]{2}:[0-9]{2}/] # => "99:99"
Note that '99:99' is accepted.
Trying to use a regex to check the range is not really very workable when dealing with something like a time value. It can be done, but the regex becomes ugly.
Here's the start of a solution. Finishing the tests for appropriate range is left as an exercise for the reader:
timeval = '00:00'[/[0-9]{2}:[0-9]{2}/]
(timeval.split(':').map(&:to_i) <=> [11,59]) <= 0 # => true
timeval = '1:00'[/[0-9]{1,2}:[0-9]{2}/]
(timeval.split(':').map(&:to_i) <=> [11,59]) <= 0 # => true
timeval = '1:00'[/[0-9]{1,2}:[0-9]{2}/]
(timeval.split(':').map(&:to_i) <=> [11,59]) <= 0 # => true
timeval = '0:99'[/[0-9]{1,2}:[0-9]{2}/]
(timeval.split(':').map(&:to_i) <=> [11,59]) <= 0 # => true
timeval = '99:99'[/[0-9]{1,2}:[0-9]{2}/]
(timeval.split(':').map(&:to_i) <=> [11,59]) <= 0 # => false
Alternately, you might want to look into using some <select>
popups for the values, or a jQuery plugin that is designed for time input, or something like validates_timeliness
or validates_date_time
. I also found time_select with 12 hour time and Time Zone in Ruby on Rails. You can search Stack Overflow too.
Your regex would be /\d\d:\d\d/
, but I'm not sure how to use regular expressions in Ruby.
精彩评论