0

I'm trying to combine start_date, start hour, and start_minute virtual attributes from my Event form, in order to create a start_datetime attribute (which is stored in the database).

I have (via STI) several subclasses of Event; let's call them TrainingSession and WorkSession and PersonalTime.

Classes are structured as such:

class Event < ActiveRecord::Base
  ...
end

class TrainingSession < Event
  ...
end

class WorkSession < Event
  ...
end

class PersonalTime < Event
  ...
end

The relevant parts of event.rb:

class Event < ActiveRecord::Base
  attr_accessor :start_date, :start_hour, :start_minute

  validates :start_datetime, :presence => true

  before_validation :merge_attributes_for_datetime_string

  def merge_attributes_for_datetime_string
    start_datetime_string = "#{ start_date } #{ start_hour }:#{ start_minute }:00"
  end

  def start_datetime=(start_datetime_string)
    self.start_datetime = start_datetime_string
  end

  def start_date
    start_datetime.strftime("%d") if start_datetime?
  end

  def start_hour
    start_datetime.strftime("%H") if start_datetime?
  end

  def start_minute
    start_datetime.strftime("%M") if start_datetime?
  end
end

... and of events_controller.rb:

  def create
    @event = Event.new(event_params)
    if @event.save
      redirect_to :root, :flash => { :success => "Event added." }
    else
      redirect_to :back, :flash => { :notice => "There was an error creating the event." }
    end
  end

  private

  def event_params
    params.require(:event).permit(
      :type,
      :start_datetime,
      :start_date,
      :start_hour,
      :start_minute,
      ...
    )
  end

  def training_session_params
    params.require(:training_session).permit(
      ...
    )
  end

  def work_session_params
    params.require(:work_session).permit(
      ...
    )
  end

  def personal_time_params
    params.require(:personal_time).permit(
      ...
    )
  end

I've verified in my server logs that the correct params are being sent from the form:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"<TOKEN HERE>=", "event"=>{"start_date" => "2013-08-23", "start_hour"=>"15", "start_minute"=>"00", "type"=>"PersonalTime"}, "commit"=>"Add Personal Time"}

Yet every time I try to create an Event (of any type), I get the notice There was an error creating the event. (as per my create method). If I comment out validates :start_datetime, the event is created, but with start_datetime of nil.

This has to mean the start_datetime string isn't being properly merged from the virtual attributes, but I can't figure out why.

What am I missing here? Is there a better way to set start_datetime?

jasonmklug
  • 1,584
  • 2
  • 15
  • 28

1 Answers1

0

Based on what you've posted, I don't see where you are calling the start_datetime method.

Instead of defining a new method, you could do the merging in your start_datetime method as follows:

before_validation :merge_attributes_for_datetime_string

def merge_attributes_for_datetime_string
  self.start_datetime = "#{ start_date } #{ start_hour }:#{ start_minute }:00"
end
vee
  • 38,255
  • 7
  • 74
  • 78
  • Shouldn't the existing the `start_datetime=(value_from_other_method)` method acting as setter? (At least *working*, if not the cleanest way to handle it) – jasonmklug Aug 23 '13 at 21:14
  • ... Also, if I just use `start_datetime` as my method name, it interferes any time I want to get the `start_datetime` attribute from the database. – jasonmklug Aug 23 '13 at 21:21
  • @jasonmklug, Yes you are right, in that case it will cause problems. So you're method name `merge_attributes_for_datetime_string` would be correct in this case. – vee Aug 23 '13 at 21:28
  • For your first question, `start_datetime=(value_from_other_method)` is a setter you've defined but it's not getting called anywhere, is it? – vee Aug 23 '13 at 21:29
  • I'm using (or trying to use, at least) the `:before_validation` callback to handle that. – jasonmklug Aug 23 '13 at 21:33
  • Right, your `before_validation` sets `start_datetime_string` not `start_datetime`. – vee Aug 23 '13 at 21:35