我试图创建一个"可组合的"文章模型,用户可以创建Article
,然后添加任意数量的不同"块",例如:a TextBlock
,VideoBlock
,最后是GalleryBlock
1}}。
我希望能够做到这样的事情:
a = Article.find(1)
text = TextBlock.new
text.content = "blah"
a.blocks << text
puts a.blocks
# =>[TextBlock, VideoBlock, ...]
TextBlock
,VideoBlock
和GalleryBlock
不同,使用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)
答案 0 :(得分:0)
目前,您的加入表与Article
之间没有明确的关系。由于它根据您的查询查找Section
个对象,因此您可以先调整Article
类作为has_many :article_blocks, as: :section
的部分。
其次,因为has_one
与TextBlock
有ArticleBlock
关系,请确保语法为has_one :article_block, as: :block