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