I have a Reservation model that takes an appointment attribute as date
and has a virtual attribute duration
that indicates how long the appointment will take. Th开发者_Python百科e real attribute, booking_end
takes a Time that is referenced all over my application. However, for ease of input, we use duration instead of choosing another Time
. The fields are below:
def duration
( (booking_end - date) / 1.hour ).round( 2 ) rescue nil
end
def duration=(temp)
if ( true if Float(temp) rescue false )
self.booking_end = time_round(date + temp.to_f.hours, 15.minutes)
else
errors.add(:duration, "must be a number, stated in hours.")
self.booking_end = nil
end
end
The whole thing fails when I reference the date
field while creating a new record. I get a 'nil' error because date hasn't been initialized. How can I fix this problem? The rest of this works when updating existing records.
When you call Reservation.new(:date => date, :duration => duration) ActiveRecord::Base assigns attributes values this way (see assign_attributes method):
attributes.each do |k, v|
...
respond_to?("#{k}=") ? send("#{k}="", v)
...
Hash#each method iterates through the values the way that :duration key is accessed before :date one, so date is nil inside the duration= method:
ruby-1.8.7-p302 > {:date => Date.today, :duration => 5}.each do |key,value|
ruby-1.8.7-p302 > puts "#{key} = #{value}"
ruby-1.8.7-p302 ?> end
duration = 5
date = 2010-11-17
So you'll have to call duration= after initialization.
Or you can redefine Reservation#initialize to call super with :date and then update_attributes with the rest of parameters.
I tried to initialize the model with
Reservation.new(params[:reservation][:date])
and then call update_attributes
on it. This works in console, but not otherwise. The only workaround that seems to take hold is stripping duration out of the params hash and then passing it back before save. This seems really stupid, though, and probably not the right or Rails way to do things. Using 4 lines where one should suffice.
duration = params[:reservation][:duration]
params[:reservation].delete('duration')
@reservation = Reservation.new(params[:reservation])
@reservation.duration = duration
# Then go to save, etc.
Is there a different way to initialize the model or perhaps access the attributes hash from inside the model?
精彩评论