0

I'm separating a datetime column (which yes, I've named 'datetime'... maybe that's too confusing) into two virtual attributes, date_field and time_field.

Then using this SO answer I'm recombining the two in a before_save callback.

However, now validation always fails with "can't be blank" whether or not I've filled in the date_field or time_field

Here's my model:

class SomeModel < ActiveRecord::Base

  validates :date_field, :time_field, presence: true

  before_save :convert_to_datetime

  def date_field
    datetime.strftime("%d/%m/%Y") if datetime.present?
  end

  def time_field
    datetime.strftime("%I:%M%p") if datetime.present?
  end

  def date_field=(date)
    @date_field = Date.parse(date).strftime("%Y-%m-%d")
  end

  def time_field=(time)
    @time_field = Time.parse(time).strftime("%H:%M:%S")
  end

  def convert_to_datetime
    self.datetime = DateTime.parse("#{@date_field} #{@time_field}")
  end

end

Edit:

Here's a little new information after investigation:

1) Per xmpolaris's comment, I tried @date_field || datetime.present? datetime.strftime("%d/%m/%Y") : nil, but that returns nil

2) I replaced before_save with before_validation and that gave me a 500 invalid date error.

3) I've inspected the params with byebug and they look like this:

(byebug) p params[:date_field]
"2014-02-10"
(byebug) p params[:time_field]
"11:30"

Is that the correct format for Rails?

Community
  • 1
  • 1
niftygrifty
  • 3,452
  • 2
  • 28
  • 49
  • 2
    the attribute readers (date_field, time_field) methods always return nil when you create new record. that's why it fails. you must return virtual attribute if its value is available, otherwise try to read from datetime attribute. e.g. @date_field || datetime.present? datetime.strftime("%d/%m/%Y") : nil – Chen Feb 03 '14 at 07:55
  • Your comment makes a lot of sense to me... but the problem persists exactly as I described even after implementing your suggestion. – niftygrifty Feb 03 '14 at 12:17

2 Answers2

2

The problem I can see is:


Not Set

before_save runs after validation (before_validation runs before validation)

I see you're using Ruby setters & writers to create the virtual attributes. However, your date_field and time_field setters are only running if datetime is present

From your code, datetime is only present when you set the datetime attribute in your before_save callback, which means you're not going to have datetime available for your setters

I would try this:

class SomeModel < ActiveRecord::Base
    before_validation :convert_to_datetime
end

Although might help a little, I don't think this will work completely

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Thanks for the helpful comment! I tried `before_validation`, but it gives me a 500 date invalid error, for both valid inputs and missing inputs. – niftygrifty Feb 03 '14 at 12:12
0

After a big headache, it turns out I needed to change my template from this...

<input type="text" id="time_field" name="time_field">

to this:

<input type="text" id="time_field" name="lesson[time_field]">

The parameters were not even being set in the first place.

Does anyone have any idea why this is necessary? And if it's possible to change this behavior?

Additionally, xmpolaris was right in his comment. It was also necessary to change my getters to:

def date_field
  @date_field || datetime ? datetime.strftime("%d/%m/%Y") : nil
end

def time_field
  @time_field || datetime ? datetime.strftime("%d/%m/%Y") : nil
end
niftygrifty
  • 3,452
  • 2
  • 28
  • 49