如何使用多态 belongs_to 关联在 Rails 中设置 MTI?

How do you set up MTI in Rails with a polymorphic belongs_to association?

为了创建一个 Short, Self Contained, Correct (Compilable), Example,假设我想执行以下操作。

我有一个博客网站。有两种类型的帖子,TextPostLinkPost。还有两种类型的用户,UserGuest。我想用 TextPostLinkPost 实现 Multiple Table Inheritance,我的意思是(希望我正确使用了这个词):

每种 Post 可以属于 UserGuest。所以我们有一个多态的belongs_to情况。

我的问题是如何实现这些目标。

tried下面的,但是不行

class Post < ApplicationRecord
  self.abstract_class = true

  belongs_to :author, polymorphic: true # user or guest
  validates :title, :author_id, :author_type, presence: true
end

class TextPost < Post
  validates :content, presence: :true
end

class LinkPost < Post
  validates :url, presence: :true
end

class User < ApplicationRecord
  has_many :text_posts, as: :author
  has_many :link_posts, as: :author
  validates :name, presence: true
end

class Guest < ApplicationRecord
  has_many :text_posts, as: :author
  has_many :link_posts, as: :author
end

class CreateTextPosts < ActiveRecord::Migration[6.1]
  def change
    create_table :text_posts do |t|
      t.string :title
      t.string :content
      t.references :author, polymorphic: true

      t.timestamps
    end
  end
end

class CreateLinkPosts < ActiveRecord::Migration[6.1]
  def change
    create_table :link_posts do |t|
      t.string :title
      t.string :url
      t.references :author, polymorphic: true

      t.timestamps
    end
  end
end

class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name

      t.timestamps
    end
  end
end

class CreateGuests < ActiveRecord::Migration[6.1]
  def change
    create_table :guests do |t|

      t.timestamps
    end
  end
end

控制台输出:

 :001 > user = User.create(name: 'alice')
   (1.6ms)  SELECT sqlite_version(*)
  TRANSACTION (0.1ms)  begin transaction
  TRANSACTION (0.1ms)  SAVEPOINT active_record_1
  User Create (1.2ms)  INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?)  [["name", "alice"], ["created_at", "2021-06-11 23:33:38.445387"], ["updated_at", "2021-06-11 23:33:38.445387"]]
  TRANSACTION (0.2ms)  RELEASE SAVEPOINT active_record_1
 :002'> text_post = TextPost.create(title: 'foo', content: 'lorem ipsum', author_id: 1, author_type:
'user')
Traceback (most recent call last):
        1: from (irb):2:in `<main>'
NameError (wrong constant name user)
  1. 常量的名称类似于局部变量的名称,只是它们以大写字母开头。

  2. 所有内置的classes,连同你定义的classes,都有一个与class同名的对应全局常量称为 class name.

所以在你的情况下,当你定义 User class 时,有一个常量 class nameUser,但不是 user,这就是为什么出现错误 NameError (wrong constant name user)

尝试text_post = TextPost.create(title: 'foo', content: 'lorem ipsum', author_id: 1, author_type: 'User')