2

在庫管理のRailsアプリを書いています。と がclass Product < ActiveRecord::Baseありclass Foo < Productますclass Bar < Product。Foo と Bar の動作は微妙に異なりますが、単一テーブルの継承を使用することは優れています。

問題はコントローラーとビューにあります。現在、私はそれらを完全に分離していますが、これは機能しますが、繰り返されるコードが大量に含まれています。2 つのディレクトリをコピーし、、、およびを@foo、、および に置き換えることで、文字通り一方を他方から生成できます。新しい機能を追加するとき、それらを 2 回追加するのはイライラします。そしてもちろん、DRY をしないのは Rails のやり方ではありません。@foosFoo@bar@barsBar

では、ここでの正しいアプローチは何ですか? コントローラーの場合... を作成してProductsControllerから、メタプログラミングの魔法を使用して、またはのいずれかをサブスクライブする必要がありますFooBar? それとも継承を使用しますか?/foosビューについては、製品ビューのみを使用する必要がありますが、巧妙なルーティングを使用して、個別の (およびRESTful な)/barsパスがあるように見せますか?

ありがとう。

4

3 に答える 3

0

コントローラーの継承は、素晴らしく、クリーンで、保守可能な方法です。基本コントローラーですべての主要なロジックを定義し、オブジェクトへの呼び出しを、継承コントローラーでオーバーライドできる仮想メソッドに置き換えます。

class Product < ApplicationController
  def resource
    nil
  end

  def new_resource
    nil
  end

  def do_something
    resource.do_something
  end

  def new
    @resource = new_resource
  end
end

class Foo < Product
  def resource
    @foo
  end

  def new_resource
    Foo.new
  end
end

継承は非常に保守しやすく、非常にクリーンで明確なため、この種の作業に適しています。

ビューに関しては、sharedすべての一般的なビュー パーシャルのディレクトリを作成できます。これはもう 1 つの非常に一般的なアプローチであり、手間を最小限に抑えて URL を完全に RESTful に制御できます。オブジェクトにも同様のメソッドがある場合、ビューはどのクラスを扱っているかを知る必要はありません。

上記のコントローラーで、foos/new にアクセスするユーザーは new_resource への呼び出しを開始し、新しい Foo インスタンスを構築して @resource としてページに返します。

#View:
<%= render 'shared/product_details', :locals => {:product => @resource} %>
于 2013-05-28T15:32:24.087 に答える
0

OPのさらなる説明によると、私は今自分の考えを持っています。

モデルの継承は他の OOP 言語には適していますが、Ruby では必要ありません。この場合、私の意見では、モジュールを使用するのが最善の解決策です。

Foo と Bar の 2 つのモデルが必要であり、異なる属性を持つことさえできます。

次に、モデルとコントローラーの共通メソッドを定義します

# lib/product_model.rb
module ProductModel
  def product_method_a
  end

  def product_method_b
  end
end

# lib/product_controller.rb
module ProductController
  def show
    @obj = @model.constantize.find(params[:id])
    render 'products/show' # need to explicitly specify it because this is general 
  end

  def index
    @objs = @model.constantize.scoped
    render 'products/index' # need to explicitly specify it because this is general 
  end
end

次に、これらのメソッドを Foo と Bar で使用し、必要に応じてカスタム メソッドを追加します。

class Foo < ActiveRecord::Base
  include ProductModel

  def serial_number
    # Foo's way
  end
end

class Bar < ActiveRecord::Base
  include ProductModel

  def serial_number
    # Bar's way
  end
end

コントローラー用。

class FoosController < ApplicationController
  @model = "foo"
  include ProductController
end


class BarsController < ApplicationController
  @model = "bar"
  include ProductController
end

ビューの場合、ビューで一般的な一致する変数名を使用するためだけに、ProductController は既にビューを定義しています。

<%= @obj.title %>

かなりDRYですね。

于 2013-05-28T18:21:00.980 に答える
0

コントローラーのメソッドとビューがまったく同じである場合は、それを product に移動できます。この方法ではProduct@product@products. であるため、 とでSTIID の繰り返しがないため、メンバー ルートも機能します。また、モデルが異なるため、ダック タイピングがそれぞれの正しいメソッドを呼び出します。FooBar

次に、両方の子モデルから特定のコントローラーに繰り返されていないすべてのものを移動できます。

于 2013-05-28T15:36:17.123 に答える