ruby-on-rails – 在Rails模型中设置和获取虚拟属性

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 在Rails模型中设置和获取虚拟属性前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在寻找一种方法解决以下问题:

Event模型中的两个日期时间属性

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,: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,end_at: "2012-08-30 06:00:00",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,updated_at: "2012-08-22 20:02:15"> 
1.9.3p194 :010 >

我的假设是我还需要自定义“实际”属性的setter,但我不知道如何做到这一点w / out搞砸了默认行为.思考?也许有更多的“Rails-y”“回调-y”方式来处理这个问题?

解决方法

这是我的看法.我没有使用ActiveRecord测试它,但我留下了评论.希望这可以帮助.
class Event < ActiveRecord::Base

  attr_accessible :end_at,:event_date
  attr_accessor :start_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有一个明确的模式.它可以通过元编程进行抽象,但我认为这会使示例不清楚.

原文链接:https://www.f2er.com/ruby/264998.html

猜你在找的Ruby相关文章