性传播感染帮助.需要帮助重构我的现有代码



我需要帮助实现或将其分解为单表继承(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]

你能添加你的迁移吗?

通常,我会期望这样的东西:

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

没有理由开设媒体课?只是为了执行默认范围,这不是必需的,因为您有一个单独的类音频媒体或视频媒体,它位于类型为音频媒体或视频媒体的附件中。您可以通过类名轻松访问它们。

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

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

最新更新