0

我现在有一个非常具体的困境。

给定以下模型:

class Message < ActiveRecord::Base
  attr_accessible :body, :sent_at

  belongs_to :subject
end

class Subject < ActiveRecord::Base
  attr_accessible :title

  has_many :messages
  belongs_to :last_message, :class_name => 'Message', :foreign_key => 'last_message_id'
end

在一个视图中,我想遍历主题列表并显示: - 主题标题 - sent_at 主题的最后一条消息,如下所示:

<% @subjects.each do |subject| %>
  <%= subject.title %>
  <%= subject.last_message.sent_at %>
<% end %>

问题是:subject.last_message 有时可能为零。在这种情况下,上面的代码会抛出异常。

那么:最好的解决方案是什么?我可以看到 3 种可能性,但老实说,我不知道哪些被认为是好的或坏的。

1)让视图拯救它

<%= subject.last_message.sent_at rescue '' %>

2)做一个帮手

def last_message_sent_at(subject)
  return '' if subject.last_message.blank?
  subject.last_message.sent_at
end

<%= last_message_sent_at(subject) %>

3)在主题模型上制作一种“代理”

class Subject < ...
  ...
  def last_message_sent_at
    return '' if last_message.blank?
    last_message.sent_at
  end
end

<%= subject.last_message_sent_at %>

你会选择哪一个,为什么?或者还有其他我没有想到的方法?

/ 卡斯滕

4

3 回答 3

2

使用try

<%= subject.last_message.try(:sent_at) %>

所以,如果subject.last_message是 nil,你将没有输出;否则,如果它不是 nil,它将调用sent_aton方法subject.last_message

这就像您的#2想法的方便形式

文档

作为额外的想法,助手是一个糟糕的选择。理想情况下,您总是想要一个“接收器”(在 中some_class.perform()some_class是“接收器”,即它“接收”消息“执行”)。除非我需要生成 HTML,否则我会避免使用 Helpers。所以,你的#3 确实有一个接收器,但由于 Rails 提供了try,你不需要自己动手。

于 2012-09-15T08:50:30.603 回答
0

如果您有任何逻辑或操作要执行,最佳实践是将其移出您的视图(进入助手、演示者)。

由于您的问题是关于“如何在可能的 nil 实例上调用方法?”,那么try在这种情况下可能是最好的方法。因为,它已经存在并且您不需要任何额外gem的 s。

另一方面,您可以通过将render @subjects块内容放入并移动到部分中来改进代码_subject。Rails 将为您执行循环。

于 2012-09-15T12:01:38.567 回答
0

在这种情况下,最简单的事情可能是简单地检查空值......

<% @subjects.each do |subject| %>
  <%= subject.title %>
  <%= subject.last_message.sent_at if subject.last_message %>
<% end %>

或者

<% @subjects.each do |subject| %>
  <%= subject.title %>
  <%= subject.last_message && subject.last_message.sent_at %>
<% end %>
于 2012-09-15T08:59:30.347 回答