12

これが私のセットアップであり、その後に私が達成しようとしていることの説明が続きます。

class Layer < ActiveRecord::Base
  has_and_belongs_to_many :components
end

class Component < ActiveRecord::Base
  has_and_belongs_to_many :layers 
end

class ImageComponent < Component
  # I want this table to inherit from the Component table
  # I should be able to add image-specific fields to this table
end

class VideoComponent < Component
  # I want this table to inherit from the Component table
  # I should be able to add video-specific fields to this table
end

私ができるようにしたいこと:

layer.components << ImageComponent.create
layer.components << VideoComponent.create

ImageComponent実際には、とVideoComponentを実際に継承する必要があることを認識していActiveRecord::Baseます。Rails でモデルのサブクラス化を適切に実装する方法はありますか?

今、私は自分のComponentモデルをpolymorphicそのようなものImageComponentに設定していVideoComponentますhas_one :component, as: :componentable。ただし、これにより、コードに煩わしさと醜さのレイヤーが追加されます。

image_component = ImageComponent.create
component = Component.create
component.componentable = image_component
layer.components << component

これを説明する簡単な方法は、レイヤーとコンポーネントの間に habtm 関係を実装したいということだと思います。複数のタイプのコンポーネント (ImageComponent、VideoComponent など) があり、それぞれの基本構造は同じですが、関連付けられているフィールドは異なります。これを達成する方法について何か提案はありますか? 私のコードはハックっぽいので、何かが欠けているように感じます。

4

3 に答える 3

10

Rails でこれを実現する「公式」の方法は、Single Table Inheritance を使用することです。STI のサポートは ActiveRecord に組み込まれています: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#class-ActiveRecord::Base-label-Single+table+inheritance

マルチテーブル継承を使用したい場合は、自分で実装する必要があります...

于 2012-11-13T09:21:17.320 に答える
1

STI では、同じテーブルを複数のモデル クラスと共有しているため、サブクラス化されたモデルに一意のフィールド (データベース列) を持たせたい場合は、その共通テーブルで表現する必要があります。あなたの例のコメントから、これがあなたが望むものであるように見えます。

ただし、各モデルがカスタムのシリアル化されたデータを格納するために使用できるテーブルに文字列列を含めることを含む、できるトリックがあります。これを行うには、SQL 内で簡単に検索できないため、これらのデータ要素がインデックス化されていなくてもかまいません。このフィールドを と呼ぶとしましょうaux。これを親モデルに入れます:

  require 'ostruct'
  serialize :aux, OpenStruct

ここで、サブクラス化されたモデルで呼び出されたフィールドがmanager必要experienceであるとしますが、他の STI モデルはこのフィールドを必要とせず、これらの属性に基づいて検索する必要はありません。したがって、サブクラス化されたモデルでこれを行うことができます。

# gets the value
def manager
  return self.aux.manager
end

# sets the value
def manager=(value)
  self.aux.manager = value
end

 # gets the value
def experience
  return self.aux.experience
end

# sets the value
def experience=(value)
  self.aux.experience = value
end

この例では、単一テーブルの継承は引き続き正常に機能し、サブクラス化されたモデルのカスタム永続属性も取得します。これにより、複数のモデル間でコードとデータベース リソースを共有できるという利点が得られるだけでなく、各モデルに固有の属性を持たせることもできます。

于 2012-11-19T15:37:56.560 に答える