1

Tagさまざまな種類のタグが存在する抽象的な概念を考えてみましょうTopicLocationタグであること以外は無関係です。これらは共通の基本Tagプロパティを持ちますが、それ以外は異なります。

コンセプトは類似のコンセプトTopicに基づいていTagます。のような操作Topic::Updateは通常 から継承しTopic::Createますが、そのような操作も から継承する必要がありますTag::Update。Ruby は多重継承をサポートしていません。Trailblazer はこれをサポートできますか?

  • Trailblazer の操作は、提供されたハッシュbuildsの内容に基づいてサブクラスをインスタンス化できるブロックによる継承をサポートします。paramsこれは、基本クラス ( Tag) が公開されており、基本クラスを介して操作が呼び出される場合に機能します。ただし、この例では、公開クラスはTopicサブクラスです。

  • 操作はサブクラス ( ) を介して呼び出す必要がありますTopicが、その操作は共通のTag基本クラス (リバース ビルダー?) に基づいています。

これは、単一の継承によって実現できる 1 つの方法です (ただし、このアプローチの欠点を示しています)...

各タイプのタグは独自のデータベース テーブルに格納され、次のような ActiveRecord クラスがあります。

class Tag < ActiveRecord::Base 
  self.abstract_class = true
end
class Topic < Tag; end

Trailblazer の概念は同様の設計に従います。Tag操作は基本機能を提供し、より具体的な操作によってサブクラス化されます ( Topic)。Tag操作は直接使用されません。Topicたとえば、コントローラーがTopic操作を使用します。

操作はTopicから継承しますが、各操作内でのみ可能と思われるTag独自のモデルを指定する必要があり、それぞれを明示的にサブクラス化する必要があります。Topic

class Topic < Tag 
  class Create < Tag::Create
    model Topic
  end 
  class Update < Tag::Update
    model Topic
  end 
  class Delete < Tag::Delete
    model Topic
  end 
end

これに関する問題は、基本操作で定義されているコントラクトが、それを aTagではなく a であるTopicと見なし、モデルとして使用される場合に問題が発生することです。これがどこに問題があるかを示す例は、セルのビューにTopicあります。概念には、オブジェクトを操作するためのビューを提示するセルがあります。simple_form_for次のように、を使用してフォームをレンダリングします。

simple_form_for operation.contract

コントラクトはそれTag

  • そのパラメータはparams[:tag]代わりにとして送信されますparams[:topic]
  • 送信ボタンのラベルはCreate TopicではなくCreate Tagです。

operation.model送信された操作が失敗した後にレンダリングするときにフォームエラーが表示されないため、セルは使用できません(それ以外の場合は機能します)。

これを解決する方法は、次のように明示することsimple_form_forです。

simple_form_for operation.contract, as: :topic, url: topics_path ...

プロパティを に追加する場合、コントラクトTopicを拡張する必要があるため、別の問題が発生します。Tagこれを行う通常の方法はcontract do..end、操作にブロックを追加することTopic::Createです。問題が発生するのは、そのようなブロックが および からではなく対応するブロックから継承さTopic::UpdateれてTopic::Deleteいるためです。TagTopic::Create

別の方法は、サブクラス化されたTopic::Update操作を から継承することTopic::Createです。これにより、モデルを指定する必要がなくなりますが (指定するため)、操作Topic::Createによって追加されたものはすべて失われます。Tag::Update

class Update < Create
  action :update
end

は継承されていないため再指定する必要がありますが、 は継承されているため、actionで追加されたプロパティは で使用できます。Tag::UpdateTopic::CreateTopic::CreateTopic::Update

これらのスタイルはどちらも、変更が 1 つの基本クラスのみにある限り機能します。Rubyは多重継承をサポートしていないため、両方に変更があると壊れます。Delete通常は次のような操作を考えてみましょう。

class Delete < Create
  action :find
  def process(params)
    # validate params and then delete
  end
end

もしそうなら、どちらかである可能性がありTag::DeleteますTopic::Delete

  class Delete < Tag::Delete
    model Topic
  end 

また

class Delete < Create
  action :find
end

前者の場合、Topic::Deleteは によって追加されたプロパティを認識せずTopic::Create、後者の場合は で定義されたメソッドTopic::Deleteを欠いています。processTag::Delete

Trailblazer の概念が別の概念を継承し、その操作を拡張するにはどうすればよいでしょうか?

4

2 に答える 2

1

モジュールを使用することで、多重継承の効果を得ることができます。

最初に ActiveRecord オブジェクトを次のように定義します。

class Topic < ActiveRecord::Base; end
class Location < ActiveRecord::Base; end

Tag基本抽象クラスはなくなり、Tag次のようなモジュールとして定義できるようになりました ( app/concepts/tag/crud.rb):

module Tag
  module Create
    def self.included(base)
      base.send :include, Trailblazer::Operation::Model
      base.send :model, base.parent # e.g. Thing::Tag => Thing
      base.send :contract, Form
    end

    class Form < Reform::Form
      property ...
    end

    def process(params)
      ...
    end
  end
  module Update
    def self.included(base)
      base.send :action, :update
    end
  end
  module Delete
    def self.included(base)
      base.send :action, :find
    end
    def process(params)
      ...
    end
  end
end

include Model通常は操作クラス ( やなどcontract)内に配置されるコードは、self.includedメソッド内に配置されるため、包含クラスのスコープ内で実行されます。モジュールのメソッド内からインクルード クラスでそのようなメソッドを呼び出すには、 rubysendメソッドを使用する必要がありますself.included

このTagモジュールを使用すると、Topicタグは次のようになります ( app/concepts/tag/topic/crud.rb)

class Topic
  class Create < Trailblazer::Operation
    include Tag::Create
    contract do
      property ...
    end
  end
  class Update < Create
    include Tag::Update
  end
  class Delete < Create
    include Tag::Delete
    def process(params)
      ....
      super
    end
  end
end

これにより、コントラクトにプロパティを追加するTagによるコントラクトの拡張と、invoke を呼び出す例のようなメソッドのさらなるカスタマイズが可能になります。さらに、コントラクトはそれが であることを認識し、適切に機能するようになります。Topic::CreateTagDelete::processsuperTag::Delete::processTopicsimple_form

于 2016-04-16T18:53:40.793 に答える