title: Setting & getting virtual attributes in Rails model
body: <p>I'm looking for a rails-y way to approach the following:</p>
  
  <p>Two <code>datetime</code> attributes in an <strong>Event</strong> model:</p>
  
  <pre><code>start_at: datetime
  end_at:   datetime
  </code></pre>
  
  <p>I would like to use 3 fields for accessing them in a form:</p>
  
  <pre><code>event_date
  start_time
  end_time
  </code></pre>
  
  <p>The problem I'm having is how to keep the actual <em>and</em> the virtual attributes in "sync" so the model can be updated via the form and/or directly via <code>start_at</code> &amp; <code>end_at</code>.</p>
  
  <pre><code>class Event &lt; ActiveRecord::Base
    attr_accessible :end_at, :start_at, :start_time, :end_time, :event_date
      attr_accessor :start_time, :end_time, :event_date
  
    after_initialize  :get_datetimes # convert db format into accessors
    before_validation :set_datetimes # convert accessors into db format
  
    def get_datetimes
      if start_at &amp;&amp; end_at
        self.event_date ||= start_at.to_date.to_s(:db)   # yyyy-mm-dd 
        self.start_time ||= "#{'%02d' % start_at.hour}:#{'%02d' % start_at.min}" 
        self.end_time   ||= "#{'%02d' % end_at.hour}:#{'%02d' % end_at.min}" 
      end
    end
  
    def set_datetimes
      self.start_at = "#{event_date} #{start_time}:00"
      self.end_at   = "#{event_date} #{end_time}:00"
    end
  end
  </code></pre>
  
  <p>Which works: </p>
  
  <pre><code>1.9.3p194 :004 &gt; e = Event.create(event_date: "2012-08-29", start_time: "18:00", end_time: "21:00")
  
   =&gt; #&lt;Event id: 3, start_at: "2012-08-30 01:00:00", end_at: "2012-08-30 04:00:00",  created_at: "2012-08-22 19:51:53", updated_at: "2012-08-22 19:51:53"&gt; 
  </code></pre>
  
  <p>Until setting actual attributes directly (<code>end_at</code> set back to <code>end_time</code> on validation):</p>
  
  <pre><code>1.9.3p194 :006 &gt; e.end_at = "2012-08-30 06:00:00 UTC +00:00"
   =&gt; "2012-08-30 06:00:00 UTC +00:00" 
  1.9.3p194 :007 &gt; e
   =&gt; #&lt;Event id: 3, start_at: "2012-08-30 01:00:00", end_at: "2012-08-30 06:00:00", created_at: "2012-08-22 19:51:53", updated_at: "2012-08-22 19:51:53"&gt; 
  1.9.3p194 :008 &gt; e.save
     (0.1ms)  BEGIN
     (0.4ms)  UPDATE "events" SET "end_at" = '2012-08-30 04:00:00.000000', "start_at" = '2012-08-30 01:00:00.000000', "updated_at" = '2012-08-22 20:02:15.554913' WHERE "events"."id" = 3
     (2.5ms)  COMMIT
   =&gt; true 
  1.9.3p194 :009 &gt; e
   =&gt; #&lt;Event id: 3, start_at: "2012-08-30 01:00:00", end_at: "2012-08-30 04:00:00", created_at: "2012-08-22 19:51:53", updated_at: "2012-08-22 20:02:15"&gt; 
  1.9.3p194 :010 &gt; 
  </code></pre>
  
  <p>My assumption is that I also need to <strong>customize the "actual" attribute's setters</strong> but I'm not sure how to do that w/out screwing up default behavior. Thoughts? Perhaps there a more "Rails-y" "callback-y" way to handle this?</p>