6

私は以下にアプローチするためのRails-yの方法を探しています:

Eventモデルの2 つのdatetime属性:

start_at: datetime
end_at:   datetime

フォームでそれらにアクセスするために 3 つのフィールドを使用したいと思います。

event_date
start_time
end_time

私が抱えている問題は、実際の属性start_at仮想属性を「同期」状態に保ち、フォームを介して、および/または&を介して直接モデルを更新できるようにする方法end_atです。

class Event < 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 && 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

どちらが機能しますか:

1.9.3p194 :004 > e = Event.create(event_date: "2012-08-29", start_time: "18:00", end_time: "21:00")

 => #<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"> 

実際の属性を直接設定するまで (検証時にend_at戻す):end_time

1.9.3p194 :006 > e.end_at = "2012-08-30 06:00:00 UTC +00:00"
 => "2012-08-30 06:00:00 UTC +00:00" 
1.9.3p194 :007 > e
 => #<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"> 
1.9.3p194 :008 > 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
 => true 
1.9.3p194 :009 > e
 => #<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"> 
1.9.3p194 :010 > 

「実際の」属性のセッターもカスタマイズする必要があると思いますが、デフォルトの動作を台無しにすることなくそれを行う方法がわかりません。考え?おそらく、これを処理するためのより「Rails-y」「callback-y」な方法がありますか?

4

2 に答える 2

6

これが私の見解です。ActiveRecord でテストしていませんが、コメントを残しました。お役に立てれば。

class Event < ActiveRecord::Base

  attr_accessible :end_at, :start_at, :start_time, :end_time, :event_date
  attr_accessor :start_time, :end_time, :event_date

  def start_time
    @start_time || time_attr_from_datetime(start_at)
  end

  def start_time=(start_time_value)
    @start_time = start_time_value
    set_start_at
  end

  def end_time
    @end_time || time_attr_from_datetime(end_at)
  end

  def end_time=(end_time_value)
    @end_time = @end_time_value
    set_end_at
  end

  def event_date
    @event_date || start_at.to_date.to_s(:db)
  end

  def event_date=(event_date_value)
    @event_date = event_date_value
    set_start_at
    set_end_at
  end

  def start_at=(start_at_value)
    write_attribute(:start_at, start_at_value)  # Maybe you need to do write_attribute(:start_at, DateTime.parse(start_at_value)) here ???
    @start_time = time_attr_from_datetime(start_at)
  end

  def end_at=(end_at_value)
    write_attribute(:end_at, end_at_value)  # Maybe you need to do write_attribute(:end_at, DateTime.parse(end_at_value)) here ???
    @end_time = time_attr_from_datetime(end_at)
  end

  private
  def set_start_at
    self.start_at = DateTime.parse("#{event_date} #{start_time}:00")
  end

  def set_end_at
    self.end_at = DateTime.parse("#{event_date} #{end_time}:00")
  end

  def time_attr_from_datetime(datetime)
    "#{'%02d' % datetime.hour}:#{'%02d' % datetime.min}"
  end
end

編集: start_time と end_time の取得と設定には明確なパターンがあります。メタプログラミングで少し抽象化することもできますが、それでは例がわかりにくくなると思いました。

于 2012-08-22T23:23:50.860 に答える
0

「仮想」属性をまったく「キャッシュ」しないだけです。特に、仮想属性を「設定可能」にする必要がなく、「取得可能」にする必要がある場合は、例のようになります。

  def event_date
    start_at.to_date.to_s(:db)   # yyyy-mm-dd 
  end
  def start_time
     "#{'%02d' % start_at.hour}:#{'%02d' % start_at.min}" 
  end
  def end_time
     "#{'%02d' % end_at.hour}:#{'%02d' % end_at.min}" 
  end

キャッシュを開始するとすぐに、キャッシュされた値の無効化について心配する必要があります。基本的には、「キャッシュされた値の無効化」の問題があります。元の設計を機能させる方法はいくつかありますが、そこで行われている計算は、メモ化/キャッシュによる複雑さの追加を正当化するほど高価ではないと思います。必要に応じて em を提供するだけで、キャッシュされた値が無効になることを心配する必要はありません。

最初に提案したことを本当に本当にやりたい場合は、次のことから始めてみてください:変更された ActiveRecord 属性のコールバック? (ただし、そのstackoverflowが書かれてからRailsが変更されたかどうかはわかりません)

于 2012-08-22T20:46:08.703 に答える