RoR |抽象活动记录时的最佳实践

时间:2012-06-02 03:00:46

标签: ruby-on-rails ruby model-view-controller ruby-on-rails-3.2

我的任务是抽象/继承活动记录类。我正在制作一个博客,其中帖子是一个基础超级标题,slug日期等...你期望找到的所有冗余的东西。

这里的事情发生了变化,我希望将Post发布到许多其他子帖子类型中,例如音频帖子,视频帖子,图片帖子,香草帖子。我认为你说对了。显然,每个子类型都有各自的属性和成员。

  1. 不是为每个子帖子类型创建名称,slug等,而是继承或可能与基类接口的最佳做法是什么? (“我赞成作品而不是继承”)

  2. 一旦我弄清楚如何正确地抽象出我的模型,我想找出一些多态的方式来表达像Blog.find(1).posts这样的东西并获得所有帖子类型的数组。

  3. 我意识到这可能不是以多态方式查询所有帖子类型的性能最佳,因此可以随意采用更好的方式。

2 个答案:

答案 0 :(得分:1)

虽然我个人也喜欢构图而不是继承,但ActiveRecord却没有。在这种情况下,如果您想使用ActiveRecord提供的工具,您应该查看Single Table Inheritance,这将解决您的两个问题。但它确实使用了继承。

切换到非ActiveRecord orm可能会为您提供一种方法,而无需通过继承执行所有操作。我曾经使用了DataMapper,它更喜欢构图,过去很成功,但它不像ActiveRecord那样功能丰富,可能无法满足您的需求。

答案 1 :(得分:1)

除了单表继承之外,您还可以考虑使用has_one关联。

所有子类型都有一个post-info,即一般帖子名称,slug等(并且post-info属于多态的子类型)。

通过这种方式,您将拥有一个post-info表,以及每个子类型的表。

但是,在模型中你需要做更多的处理:

class PostInfo < ActiveRecord::Base
  belongs_to :post, :polymorphic => true
  # will need these 2 fields: :post_id, :post_type (might be AudioPost, ImagePost, etc)
end

class AudioPost < ActiveRecord::Base
  has_one :post_info, :as => :post

  # you may also want these:
  accept_nested_attributes_for :post_info
  delegate :name, :slug, :posted_at, :to => :post_info
end

现在,如果你想获得所有帖子,你可以:

Blog.find(1).post_infos

post_info.post # => audio_post, image_post, or whatever depending on post_type

如果您不想使用.post_infos,您还可以更改所有这些名称,例如:

class Post < ActiveRecord::Base
  belongs_to :actual_post # actual_post_id, actual_post_type
end

class AudioPost < ActiveRecord::Base
  has_one :post, :as => :actual_post
  accept_nested_attributes_for :post
  delegate :name, :slug, :posted_at, :to => :post
end

现在,你有:

posts = Blog.find(1).posts

actual_post = posts.first.actual_post # => an audio_post instance

actual_post.name # => same as actual_post.post.name, so you do not need the name field in the AudioPost model