开发者

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:

  1. 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.
  2. 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 all old_time values has been converted to the time 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜