what is ruby-on-rails' order of operations when constructing from a hash?
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
精彩评论