Rails 的自定义加入 Table 名称

Custom Join Table Name for Rails

我是 Rails 上 Ruby 的新手,我正在开发后端 API。

目前,我有 2 个 Active Record 模型,名为 BookUser

活动记录模型

class Book < ActiveRecord::Base
    has_and_belongs_to_many :users
end

class User < ActiveRecord::Base
    has_and_belongs_to_many :books
end

数据库模式模型

create_table :books do |t|
  t.string "title"
end

create_table :users do |t|
  t.string "name"
end

#User favourite books
create_join_table :users, :books do |t|
  t.index [:user_id, :book_id]
  t.index [:book_id, :user_id]
end

#User read books
create_join_table :users, :books do |t|
  t.index [:user_id, :book_id]
  t.index [:book_id, :user_id]
  t.integer "read_pages"
  t.string "status"
  t.integer "rating"
  t.datetime "start_date"
  t.datetime "finish_date"
end

问题

我想创建 2 加入 tables,其中一个用于添加到用户 收藏夹 列表的那些书, 另一本用于用户 阅读.

的书籍

两个 table 共享 user_id & book_id,然而,第二个有更多的数据,因为它是一条记录。

  1. Active Record 命名约定自动创建一个名为 users_books 的 table。所以当我迁移它时,它向我报告以下错误:

Index name 'index_books_users_on_user_id_and_book_id' on table 'books_users' already exists

  1. 如何重命名第二个连接 table 名称?

如果要为 many to many 关系保存 primary 以外的键,则应使用 has_many :through 关联。有关详细信息,请参阅 Rails guides。您的模型应如下所示:

class Book < ActiveRecord::Base
    has_many :read_books
    has_many :users, through: :read_books
end

class User < ActiveRecord::Base
    has_many :read_books
    has_many :books, through: :read_books
end

class ReadBook < ActiveRecord::Base
    belongs_to :user
    belongs_to :book
end

你也可以在 read_books 中制作一个 field/flag(is_favourite) 并在 read_books 中为

这样的收藏夹创建一个范围
scope :favourites, -> { where(is_favourite: true) }

How do I rename the second join table name?

传递 table_name: 选项:

create_join_table :users, :books, table_name: :favorite_books do |t|
  t.index [:user_id, :book_id]
end

您还需要为关联使用唯一的名称并告诉 rails 发生了什么,因为它可以从名称派生:

class User < ApplicationRecord
  has_and_belongs_to_many :books
  has_and_belongs_to_many :favorite_books, 
    join_table: 'favorite_books',
    class_name: 'Book',
    inverse_of: :favorite_books
end

class Book
  has_and_belongs_to_many :users
  # for lack of a better name?
  has_and_belongs_to_many :favorite_users, 
    join_table: 'favorite_books',
    class_name: 'User',
    inverse_of: :favorite_books
end

唯一的名称是必要的,因为如果您使用相同的名称,您只会破坏以前的关联。

但是...

has_and_belongs_to_manycreate_join_table 非常无用,因为它们不允许您访问 table 上的任何其他列,并且不提供诸如主键或时间戳。文档说:

Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.

但是您怎么知道您是否想要这些功能呢?而你被困在那里只有两个外键的 table 。如果内存使用成为问题(这不会发生),那么使用 has_many through: 并切换到 has_and_belongs_to_many 是一个更好的主意。

TLDR; has_and_belongs_to_many 糟透了。请改用 has_many through: