我有这个型号:
class Device < ActiveRecord::Base
has_many :events
def last_event
events.last
end
end
如您所见,我有一种方法可以获取设备的最后一个事件。现在,在Device模型的其他地方我有这个方法:
def place
self.last_event.place
end
现在,如果我在此设备的事件中没有任何记录,我会收到错误“nil的未定义方法'地点':NilClass”。
所以我补充道:
def place
self.last_event.place if self.last_event.present?
end
这个模式在整个应用程序中重复出现,我不得不添加“if self.last_event.present?”所以它也不会在其他地方崩溃。
我确信必须有更好的方法来处理这种事情,而无需检查last_event是否存在于何处?
有什么建议吗?
谢谢,
答案 0 :(得分:3)
try
方法(ActiveSupport的添加)允许这样做。如果在nil
对象上调用它,它也将返回nil
。因此,以下两行是等效的:
self.last_event.try(:place)
# equivalent to
self.last_event.place if self.last_event
答案 1 :(得分:0)
另一个选择是让方法返回一个响应调用的空白对象:
class Device < ActiveRecord::Base
has_many :events
def last_event
events.last || Event.new
end
def place
self.last_event.place
end
end
2.0.0p247 :001 > d = Device.new
=> #<Device id: nil, name: nil, created_at: nil, updated_at: nil>
2.0.0p247 :002 > d.place
=> nil
2.0.0p247 :003 > d.last_event
=> #<Event id: nil, device_id: nil, created_at: nil, updated_at: nil, place: nil>
这个想法是,如果一个方法总是返回一个期望类型的对象,你就不必担心后续调用遇到一个nil对象。当然,这可能会产生其他影响 - 例如需要确定您是否拥有有效对象或新对象,但稍后可以通过以下方式进行检查:
2.0.0p247 :005 > d.last_event.new_record?
=> true
答案 2 :(得分:0)
在这种情况下,您可以使用代理
delegate :last, to: events, allow_nil: true, prefix: :event
delegate :place, to: event_last, allow_nil: true