我需要帮助实现或将其分解为单表继承(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]
答案 0 :(得分:0)
通常,我会期待类似的事情:
article.medias.first.class == AudioMedia #true
是否有理由将媒体类置于适当位置?只是为了做默认范围,这不是必需的,因为你有一个独立的类AudioMedia或VideoMedia,它们存在于AudioMedia或VideoMedia类型的附件中。您可以通过他们的班级名称轻松访问它们。
顺便说一句,你应该看一下paperclip或carrier_wave。
答案 1 :(得分: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}