Как проверить, есть ли в экземпляре объект, чтобы пропустить отображение значений? - PullRequest
0 голосов
/ 21 мая 2010

Я создал полиморфную ассоциацию вокруг модели с именем status.

С некоторыми контактами будет связан статус. Многие не будут.

Если я пытаюсь вызвать состояние, когда его нет, я получаю сообщение об ошибке. Прямо сейчас, даже если я не создал статус для модели, он по-прежнему выполняет все, что находится в блоке if-end.

Вот что я пытаюсь, но у меня не получается:

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

В контроллере это определяется ниже:

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

Кстати, также, чтобы сделать код более читабельным и сухим.

Ответы [ 4 ]

0 голосов
/ 21 мая 2010

Проблема с открывающим родителем в том, что 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 %>   
0 голосов
/ 21 мая 2010

Один из вариантов - не проверять наличие статуса, предоставляя всем контактам (при создании контакта) статус по умолчанию, который ничего не делает.

Вы могли бы назвать это идиомой Null Object: объект, который вы используете там, где вы в противном случае использовали бы null (C, C ++, Java) или NULL (SQL) - это фактически то, что Smalltalk делает с nil; nil - это специальный объект, экземпляр класса UndefinedObject.

Преимущество этой идиомы состоит в том, что вам не нужно проверять и иметь специальную обработку для условия "объект не существует". Это делает код более чистым и более объектно-ориентированным, поскольку ваш экземпляр Null Object, а не вызывающий код, может определять, что делать при вызове его методов.

Вот пример Java, использующий шаблон цепочки ответственности. Chain of Responsibility в основном означает наличие списка обработчиков , каждый из которых обрабатывает что-то (команда ) или передает его следующему обработчику в цепочке. Мы сделаем обработчик Null Object, который просто ничего не делает, когда его просят что-то обработать.

Во-первых, генподряд:

interface Handler {
  void handle( Command c ) ;
}

Тогда Нулевой Обработчик с (ужасом!) Синглтоном:

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

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

Затем базовый класс для любого другого типа обработчика (здесь также используется шаблонный шаблонный шаблон, но это просто деталь реализации):

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 мы напечатали имя этого экземпляра, а затем вызвали метод печати next. Метод print в NullHandler ничего не выводит, или, возможно, «конец цепочки».

0 голосов
/ 21 мая 2010

Я действительно придумал это:

<% unless @status.empty? %>
       <p>Status: <%= @status.find(:last).status %> <%= @status.find(:last).created_at.to_s(:long) %></p>
<% end %>   
0 голосов
/ 21 мая 2010

делает его сухим:

@statuses = @contact.statuses

и

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

Если я понимаю ваш код и то, что вы пытаетесь сделать правильно, разве это вам не поможет?

<% if @statuses.length > 0 %>
       <p>Status: <%= @status.last.status %></p>
<% end %>
...