1

我有这个模型:

class Device < ActiveRecord::Base
  has_many :events

  def last_event
     events.last
  end
end

如您所见,我有一种方法可以获取设备的最后一个事件。现在,在设备模型的其他地方我有这个方法:

def place
   self.last_event.place
end

现在,如果我在此设备的事件中没有任何记录,我会收到错误“nil:NilClass 的未定义方法 `place'”。

所以我补充说:

def place
   self.last_event.place if self.last_event.present?
end

这种模式在整个应用程序中重复出现,我必须添加“if self.last_event.present?” 所以它也不会在其他地方崩溃。

我确信必须有更好的方法来处理这种事情,而无需检查 last_event 是否无处不在?

有什么建议么?

谢谢,

4

3 回答 3

3

try方法(添加了 ActiveSupport)完全可以做到这一点。如果在nil对象上调用,它也会返回nil。因此,以下两行是等价的:

self.last_event.try(:place)
# equivalent to
self.last_event.place if self.last_event
于 2013-08-11T19:15:06.537 回答
0

在这种情况下,您可以使用委托

delegate :last, to: events, allow_nil: true,  prefix: :event
delegate :place, to: event_last, allow_nil: true
于 2013-08-11T20:24:17.963 回答
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
于 2013-08-11T19:31:15.413 回答