0

我围绕一个名为 status 的模型创建了一个多态关联。

一些联系人将具有与之关联的状态。许多人不会。

如果我尝试在状态不存在时调用状态,则会出现错误。现在,即使我没有为模型创建状态,它仍然运行 if-end 块中的任何内容。

这是我正在尝试的,但它不起作用:

<% if !@status.nil? %>
       <p>Status: <%= @status.find(:last).status %></p>
<% end %>

在控制器中,它定义如下:

@status = Contact.find(@contact).statuses

顺便说一句,也开放以使代码更具可读性和 DRY。

4

4 回答 4

0

使其干燥:

@statuses = @contact.statuses

<% unless @statuses.nil? %>
       <p>Status: <%= @status.last.status %></p>
<% end %>

如果我了解您的代码以及您要正确执行的操作,这对您没有帮助吗?

<% if @statuses.length > 0 %>
       <p>Status: <%= @status.last.status %></p>
<% end %>
于 2010-05-21T03:38:48.140 回答
0

一种选择是不必检查状态是否存在,方法是为所有联系人(在创建联系人时)提供不执行任何操作的默认状态。

您可以将其称为 Null Object 惯用语:在其他情况下使用 null(C、C++、Java)或 NULL (SQL) 的对象——这实际上是 Smalltalk 对 nil 所做的;nil 是一个特殊的对象,UndefinedObject 类的一个实例。

这个习惯用法的优点是您不必检查“对象不存在”条件,也不必对其进行特殊处理。这使得代码更简洁,也更面向对象,因为您的 Null Object 实例,而不是调用代码,可以确定调用其方法时要做什么。

这是一个使用责任链模式的 Java 示例。责任链基本上意味着拥有一个处理程序列表每个处理程序都处理某些事情(一个命令)或将其传递给链中的下一个处理程序。我们将创建一个空对象处理程序,当它被要求处理某事时它什么也不做。

一、总承包:

interface Handler {
  void handle( Command c ) ;
}

然后是 Null 处理程序,带有(恐怖!)单例:

class NullHandler implements Handler {
  public static void NullHandler singleton = new NullHandler();

  void handle( Command c ) { /*no-op*/}
}

然后是其他所有类型的 Handler 的基类(这也使用了模板方法模式,这只是一个实现细节):

abstract class BaseHandler implements Handler {
  private Handler next;

  public BaseHandler( Handler next ) {
    this.next = next ;
  }

  public BaseHandler() {
    this( NullHandler.singleton ) ;
  }

  public void handle( Command c ) { 
    if( canHandle( c ) {
       doHandle( c ) ;
    } else {
       next.handle( c ) ;
    }
  }


  //Template Method hooks
  abstract boolean canHandle( Command c ) ;
  abstract void doHandle( Command c ) ;
}

所以我们在这里得到的东西是有限的——我们可以做next.handle( c ) ;而不是做if next != null next.handle( c ) ;。但随着我们添加更多代码,价值变得更加明显。

假设我们要打印我们的责任链。一种方法是在我们的代码中外部化迭代链,每次测试以查看 next == null。

但更好,更面向对象,我们可以让链自己做。同样,在BaseHandler's print 中,我们将打印该实例的名称,然后调用next's print 方法。NullHandler 中的print方法不会打印任何内容,或者可能会打印“链结束”。

于 2010-05-21T03:41:35.123 回答
0

我实际上想出了这个:

<% unless @status.empty? %>
       <p>Status: <%= @status.find(:last).status %> <%= @status.find(:last).created_at.to_s(:long) %></p>
<% end %>   
于 2010-05-21T04:41:03.873 回答
0

Contact.statuses 返回一个数组的打开父级的问题 - 总是。如果联系人没有状态,则数组为空 ([]) - 但它不为零。

我看到你empty?现在正在使用。

我建议通过将事物移至模型来使其更加干燥。例如,采用这个简单的方法:

class Contact < ActiveRecord::Base
  ...
  def last_status
    @last_status ||= statuses.last
  end
end

有了这个,你就不必计算@statuses控制器上的变量了。它还将缓存statuses.last在 上@last_status variable,因此 statuses.last 只被调用一次。@last_status ||=如果您不希望发生这种情况,请删除该部分。

然后您的视图可以或多或少地按照您最初的意图完成:

<% unless @contact.last_status.nil? %>
  <p>Status: <%= @contact.last_status.status %> <%= @contact.last_status.created_at.to_s(:long) %></p>
<% end %>   
于 2010-05-21T07:43:18.643 回答