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

问题描述

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

我有一个博客网站。有两种类型的帖子,TextPostLinkPost。还有两种类型的用户UserGuest。我想用 TextPostLinkPost 实现 @L_404_1@,我的意思是(希望我正确使用该术语):

  • 在模型级别,我将拥有 PostTextPostLinkPostTextPostLinkPost 将从 Post 继承。
  • 数据库级别,我将拥有 TextPostLinkPost 的“叶”模型表,但没有 Post 的表。

每种类型的 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
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. 所有内置类,以及您定义的类,都有一个对应的全局常量,其名称与名为 class name 的类相同。

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

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