首页 > 解决方案 > 如何在 Rails 中使用多态的 belongs_to 关联设置 MTI?

问题描述

为了创建一个简短的、自包含的、正确的(可编译的)示例,假设我想做以下事情。

我有一个博客网站。有两种类型的帖子,TextPostLinkPost。还有两种类型的用户,UserGuest。我想用and实现多表继承,我的意思是(希望我正确使用了这个术语):TextPostLinkPost

每种类型都Post可以属于 aUser或 a Guest。所以我们有一个多态的belongs_to情况。

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

尝试了以下方法,但它不起作用。

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)

标签: ruby-on-railsinheritanceassociationspolymorphic-associationsmulti-table-inheritance

解决方案


  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')


推荐阅读