开发者

what is ruby-on-rails' order of operations when constructing from a hash?

开发者 https://www.devze.com 2023-01-06 06:16 出处:网络
I have an Attendance model that allows the user to enter a starting, ending and break time, each as a ruby开发者_C百科 Time object.Each attendance also has a day (ruby Date object).I want the \'Date\'

I have an Attendance model that allows the user to enter a starting, ending and break time, each as a ruby开发者_C百科 Time object. Each attendance also has a day (ruby Date object). I want the 'Date' elements of the times to be the same, so I override the assignment operators like this:

def startTime= (t)
  self[:startTime] = Time.mktime(day.year, day.month, day.day, t.hour, t.min)
end
def endTime= (t)
  self[:endTime] = Time.mktime(day.year, day.month, day.day, t.hour, t.min)
end
def breakTime= (t)
  self[:breakTime] = Time.mktime(day.year, day.month, day.day, t.hour, t.min)
end

My problem is that my tests fail only when I override the breakTime= function. They all fail on calls to new, i.e. att = Attendance.new @valid_attributes, specifically at breakTime=:

undefined method `year' for nil:NilClass

Apparently, breakTime= is getting called before the day is defined on the object, even though, startTime= and endTime= are not getting called so early. I realize this overriding is probably inelegant, but I'm pretty new to rails, so I imagine someone has made this mistake before. How should I be doing this differently?


Instead of overriding the attribute setters, use a before_save callback to change the attributes just before saving the model:

class Attendance < ActiveRecord::Base
  before_save :update_timestamps

  protected
  def update_timestamps
    self.start_time = Time.mktime(day.year, day.month, day.day, start_time.hour, start_time.min)
    # And similarly for the other columns
  end
end

For an overview on how callbacks work, have a look at the Active Record Validations and Callbacks guide over at guides.rubyonrails.org.


Why don't you use active record callbacks . before_save can help you out here .


If you wish to stick with the override approach (which has the advantage that even unsaved models also conform with common time formatted attributes) you need to call the super class's implementation in each of yours:

def startTime= (t)
  t = Time.mktime(day.year, day.month, day.day, t.hour, t.min)
  super t
end
def endTime= (t)
  t = Time.mktime(day.year, day.month, day.day, t.hour, t.min)
  super t
end
def breakTime= (t)
  t = Time.mktime(day.year, day.month, day.day, t.hour, t.min)
  super t
end
0

精彩评论

暂无评论...
验证码 换一张
取 消