How do I allow my model to accept two different date formats?
Asked Answered
A

1

6

I'm using Ruby on Rails 5. I have the following code in my model ...

class User < ActiveRecord::Base
    ...
  attr_accessor :dob_string 

  def dob_string
    @dob_string || (self.dob ? self.dob.strftime('%m/%d/%Y') : "")  
  end

  def dob_string=(dob_s)
    date = dob_s && !dob_s.empty? ? Date.strptime(dob_s, '%m/%d/%Y') : nil 
    self.dob = date
  rescue ArgumentError
    errors.add(:dob, 'The birth date is not in the correct format (MM/DD/YYYY)')
    @dob_string = dob_s
  end

Despite my instructions, sometimes users enter the date in the form MM-DD-YYYY. So what I want to do is allow my model to accept both formats, MM/DD/YYYY or MM-DD-YYYY, but not mixed, that is MM/DD-YYYY shoud still be illegal. How do I modify my model so that it can accept either format?

Alb answered 21/2, 2017 at 17:29 Comment(1)
please update your post since there are too many spelling mistakes and even edit option is disabled for us :-)Immolate
T
0

I think this might do what you need:

class User < ActiveRecord::Base
  def dob_string
    @dob_string || (dob ? dob.strftime("%m/%d/%Y") : "")
  end

  def dob_string=(dob_s)
    unless convert_preferred_date(dob_s) || convert_acceptable_date(dob_s)
      errors.add(:dob, 'The birth date is not in the correct format (MM/DD/YYYY)')
      @dob_string = dob_s
    end
  end

  private

  def convert_preferred_date(dob_s)
    convert_date(dob_s, "%m/%d/%Y")
  end

  def convert_acceptable_date(dob_s)
    convert_date(dob_s, "%m-%d-%Y")
  end

  def convert_date(dob_s, format)
    self.dob = (dob_s && !dob_s.empty? ? Date.strptime(dob_s, format) : nil)
  rescue ArgumentError
    nil
  end
end

It's a little inelegant, but I can't think of a way to do only two date formats. If you're prepared to accept any human-readable data format, there's a much simpler way to do this.

Please test this thoroughly in your own app. I was just messing around with this in the Rails console, and I might not have tested every case. Hopefully this helps.

Tortricid answered 1/3, 2017 at 23:14 Comment(6)
I save the invalid date because if someone enters an invalid date in the view when they are returned to the view they shoudl see the invalid value they entered. Make sense?Alb
That makes sense for sure. I wasn't thinking about how you might use this in the view. Does the answer help you?Tortricid
While it does parse dates correctly like "01-01-1980" and "01/01/1980", it also parses dates "01/01-1980" and that's not what I want. I only want it to accept correct dates if they are using all dashes or all slashes but not a combination of both.Alb
Dave, my humblest apologies. I had commented out the line that starts "errors.add", so I suspect that maybe the code was working, but it wasn't reporting the errors. I fixed the code above. Also, the return value of the dob_string= method makes it look like it's parsing the date, but it isn't. (Make sure you test different formats with different dates or it can be hard to tell if the code really worked or not.)Tortricid
The new code doesn't accept "01/01-1980," which is good, but it is rejecting "01-01-1980," which I want.Alb
I've certainly learned that I shouldn't try to write 40 lines of code without writing proper automated unit tests. :-). I have revised the code above so it doesn't set the error unless both formats fail. It was setting the error when the first format failed, even if the second format succeeded. I hope this works better.Tortricid

© 2022 - 2024 — McMap. All rights reserved.