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

Contact.statuses が配列を返すオープニングの親の問題 - 常に。連絡先にステータスがない場合、配列は空 ([]) ですが、nil ではありません。

今使っていることが分かりますempty?

物事をモデルに移動することで、さらに DRY にすることをお勧めします。たとえば、次の簡単な方法を使用します。

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

@statusesこれにより、コントローラーで変数を計算する必要がなくなります。にもキャッシュstatuses.lastされる@last_status variableため、statuses.last は 1 回だけ呼び出されます。@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 に答える
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

1 つのオプションは、(連絡先が作成されたときに) すべての連絡先に何もしない既定の状態を与えることによって、状態の存在を確認する必要がないことです。

これを Null オブジェクトのイディオムと呼ぶことができます。つまり、通常は null (C、C++、Java) または NULL (SQL) を使用する場所で使用するオブジェクトです。実際、これは Smalltalk が nil に対して行うことです。nil は UndefinedObject クラスのインスタンスである特別なオブジェクトです。

このイディオムの利点は、「オブジェクトが存在しない」状態をチェックしたり、特別な処理をしたりする必要がないことです。これにより、よりクリーンなコードが作成され、よりオブジェクト指向にもなります。これは、呼び出しコードではなく Null オブジェクト インスタンスが、そのメソッドが呼び出されたときに何をすべきかを決定できるためです。

以下は、Chain of Responsibility パターンを使用した Java の例です。責任の連鎖とは基本的に、それぞれが何か (コマンド) を処理するか、チェーン内の次のハンドラに渡すハンドラのリストを持つことを意味します。何かを処理するように求められたときに何もしない Null オブジェクト ハンドラを作成します。

まず、一般契約:

interface Handler {
  void handle( Command c ) ;
}

次に、(恐ろしい!)シングルトンを備えたNull Handler:

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 ) ;。しかし、コードを追加するにつれて、その価値はより明確になります。

責任の連鎖を印刷したいとしましょう。これを行う 1 つの方法は、コード内で Chain の反復を外部化し、毎回 next == null かどうかをテストすることです。

しかし、より良いことに、よりオブジェクト指向的に、Chain 自体に任せることができます。の printでは、そのインスタンスの名前を出力してから、の print メソッドBaseHandlerを呼び出します。NullHandlernextのメソッドは何も出力しないか、おそらく「チェーンの終わり」を出力します。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 に答える