连接表内的多态关系

时间:2015-05-14 06:54:11

标签: ruby-on-rails

我试图创建一个"可组合的"文章模型,用户可以创建Article,然后添加任意数量的不同"块",例如:a TextBlockVideoBlock,最后是GalleryBlock 1}}。

我希望能够做到这样的事情:

a = Article.find(1)
text = TextBlock.new
text.content = "blah"
a.blocks << text

puts a.blocks
# =>[TextBlock, VideoBlock, ...]

TextBlockVideoBlockGalleryBlock不同,使用STI是不合适的。

我认为通过联接表可以做我想做的事情,其中​​一个关系是多态的,但我还没有能够让它工作。

这里大概是我在哪里,但它不会起作用:

class Article < ActiveRecord::Base
  has_many :article_blocks
  has_many :blocks, through: :article_blocks
end

class TextBlock < ActiveRecord::Base
  has_one :article_block, as: :block
  has_one :article, through: :article_block
end

class ArticleBlock < ActiveRecord::Base
  belongs_to :article
  belongs_to :block, polymorphic: true
end

我的架构

ActiveRecord::Schema.define(version: 20150520030333) do

  create_table "article_blocks", force: :cascade do |t|
    t.integer  "article_id"
    t.integer  "block_id"
    t.string   "block_type"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_index "article_blocks", ["article_id"], name: "index_article_blocks_on_article_id"
  add_index "article_blocks", ["block_type", "block_id"], name: "index_article_blocks_on_block_type_and_block_id"

  create_table "articles", force: :cascade do |t|
    t.string   "title"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "text_blocks", force: :cascade do |t|
    t.text     "content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

如果我尝试访问文章块,我会收到此错误:

irb> x = Article.new
=> #<Article id: nil, title: nil, created_at: nil, updated_at: nil>
irb> x.blocks
ActiveRecord::HasManyThroughAssociationPolymorphicSourceError: Cannot have a has_many :through association 'Article#blocks' on the polymorphic object 'Block#block' without 'source_type'. Try adding 'source_type: "Block"' to 'has_many :through' definition.

如果我添加source_type: "Block",我会收到类型错误(因为该类不存在)。如果我将其更改为source_type: "ArticleBlock",则代码不会失败,但我无法将TextBlocks插入其中,因为文本块的类型错误。

x = Article.new
=> #<Article id: nil, title: nil, created_at: nil, updated_at: nil>
irb> x.blocks
=> #<ActiveRecord::Associations::CollectionProxy []>
irb> t = TextBlock.new
=> #<TextBlock id: nil, content: nil, created_at: nil, updated_at: nil>
irb> t.content = "This is my text content"
=> "This is my text content"
irb> x.blocks << t
ActiveRecord::AssociationTypeMismatch: ArticleBlock(#70362257715180) expected, got TextBlock(#70362257254480)

1 个答案:

答案 0 :(得分:0)

目前,您的加入表与Article之间没有明确的关系。由于它根据您的查询查找Section个对象,因此您可以先调整Article类作为has_many :article_blocks, as: :section的部分。

其次,因为has_oneTextBlockArticleBlock关系,请确保语法为has_one :article_block, as: :block