3

我需要帮助实现或将其分解为单表继承 (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可能会很臃肿,并且有太多不同的逻辑需要为不同的 media_types 做不同的事情。所以我试图通过这样做将它们分开:

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

看起来您缺少与 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    

现在您所有的附件都在一个字段中

article.attachments

例如,如果您只需要视频

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

你能添加你的迁移吗?

通常,我会期待这样的事情:

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

设置媒体类是否有原因?只是为了执行默认范围,这不是必需的,因为您有一个单独的 AudioMedia 或 VideoMedia 类,它们位于 AudioMedia 或 VideoMedia 类型的附件中。您可以通过它们的类名轻松访问它们。

顺便说一下,你应该看看回形针或carrier_wave。

于 2013-10-24T15:44:24.020 回答