3

これを実装するか、Single-Table-Inheritance (STI) に分割するのに助けが必要です。私はそれについて読んだことがありますが、これが正しい方法であるかどうかはまだよくわかりません. 実装するための提案があれば。もしくは、今の自分と大きく違っていても、アドバイスをお願いします。

したがって、通常、次のクラス(すべてのモデル)があります。

class Article < ActiveRecord::Base
  has_many :attachments

  has_many :medias
  has_one :banner

  accepts_nested_attributes :medias
  ...
end

class Attachment < ActiveRecord::Base
  belongs_to :article
end

class Media < Attachment
  default_scope { where(attachment_type: 'media') }

  def audio?; media_type == 'audio'; end
  def video?; media_type == 'video'; end

  validate :embed_url, presence: true if :video?

  def path
    if audio?
      # Different audio path
    elsif video?
      # Different video path
    end
  end

  after_commit :process_audio_file
  def process_audio_file; ...; end

  after_commit :process_video_file
  def process_video_file; ...; end
end

class Banner < Attachment
  default_scope { where(attachment_type: 'banner') }
  ...
end

そして、通常、それも正常に機能します..

article = Article.first
first_media = article.medias.first
banner = article.banner

しかし、それMediaはおそらく肥大化し、さまざまなメディアタイプに対してさまざまなことを行うさまざまなロジックが多すぎることに気付きました。だから私はこれを行うことによってそれらを分離しようとしました:

class Article < ActiveRecord::Base
  has_many :attachments

  has_many :medias
  has_one :banner

  accepts_nested_attributes_for :medias
end

class Attachment < ActiveRecord::Base
  belongs_to :article
end

class Media < Attachment
  default_scope { where(attachment_type: 'media') }
end

class AudioMedia < Media
  default_scope { where(media_type: 'audio') }

  def path
    # Audio path
  end

  after_commit :process_audio_file
  def process_audio_file; ...; end
end

class VideoMedia < Media
  default_scope { where(media_type: 'video') }

  validate :embed_url, presence: true

  def path
    # Video path
  end

  after_commit :process_video_file
  def process_video_file; ...; end
end

ここで、ロジックを互いに分離しました。すごい!しかし、今では次のような問題がいくつかあります。

article = Article.first
first_media = article.medias.first

これを行うことで、私はMediaクラスにいるだけです...AudioMediaクラスと言うには、私がしなければならないことは次のとおりです。

"#{first_media.media_type}Media".constantize.find(first_media.id)

また、nested_attributes を機能させるには、定義する必要があります

accepts_nested_attributes_for :audio_medias
accepts_nested_attributes_for :video_medias

それを正しく機能させるには?次に、それらの関係を次のように定義する必要があります。

has_many :medias
has_many :audio_medias
has_many :video_medias

何かアドバイス?ありがとう、乾杯!

編集

関連するテーブルとフィールドを追加

articles
  id
  [some_other_fields]

attachments
  id
  article_id
  attachment_type # media, banner, etc...
  media_type # audio, video, etc...
  [some_other_fields]
4

2 に答える 2

0

移行を追加していただけますか?

通常、私は次のようなものを期待します:

article.medias.first.class == AudioMedia #true

また、メディア クラスを配置する理由はありますか? デフォルトのスコープを実行するためだけに、タイプ AudioMedia または VideoMedia の添付ファイルに存在する別のクラス AudioMedia または VideoMedia があるため、これは必要ありません。また、クラス名で簡単にアクセスできます。

ところで、paperclip またはcarrier_wave を見てください。

于 2013-10-24T15:44:24.020 に答える
0

STI に関連する重要な何かが欠けているようです。新しい AR インスタンスを作成し、テーブルに「type」という名前の列がある場合、AR はオブジェクトのクラス名をその列に格納します。後でレコードを選択すると、AR はタイプ列の値を使用してクラスを検出し、それを構築します。

それらのスコープとオーディオを使用して、何らかの形で同様のものを実装しているように見えますか? ビデオ?メソッド。

だから最初に

rails g migration add_type_to_attachments type:string
rake db:migrate

次に、コードを次のようにします。

class Article < ActiveRecord::Base
  has_many :attachments      
  accepts_nested_attributes_for :attachments
end

class Attachment < ActiveRecord::Base
  belongs_to :article
end

class Media < Attachment

end

class AudioMedia < Media

  def path
    # Audio path
  end

  after_commit :process_audio_file
  def process_audio_file; ...; end
end

class VideoMedia < Media        
  validate :embed_url, presence: true

  def path
    # Video path
  end

  after_commit :process_video_file
  def process_video_file; ...; end
end    

すべての添付ファイルが 1 つのフィールドに表示されるようになりました

article.attachments

たとえば、ビデオのみが必要な場合

article.attachments.select{|a|a.is_a? VideoMedia}
于 2013-10-25T07:17:59.923 に答える