Activerecord/Datamapper - 有一个 child 属于多个 parents
Activerecord/Datamapper - Have one child belong to many parents
对于以下情况,您将如何设置 activerecord/datamapper 关联:
一个用户创建了一个 "bookshelf",里面有很多书(一本书 object 只有一个 isbn,用于查询 api,has_many
评论 objects 与之关联)。假设 Jack 用一本书 object 创建了一个 "bookshelf"。然后,假设 Jill 使用同一本书 object 创建了一个 "bookshelf"(它具有相同的 ID 和相同的评论)。本书 object 目前有以下代码:
class Book < ActiveRecord::Base
has_many :reviews
end
然后,当您查看一本书的页面时(从 Jack 创建的 "bookshelf" 单击 link 到它)您应该看到 same book object 当你从 Jill 的 "bookshelf" 点击 link 时(例如 "bookshelves" 都有 link 到 /books/23 因为他们有同一本书 object).
我无法通过 has_many
协会解决这个问题,因为每次用户向他们的 "bookshelf." 添加一本书时,我都需要制作一本新书,我无法理解has_and_belongs_to_many
关系,那是不是应该用在这里?我无法在 SO 上找到任何类似的问题,因此非常感谢您的帮助。
我正在使用 Rails 4 和 Ruby 2.1.
这是一张我想要完成的图:
Drawing
是的,您必须在 Bookshelf 和 Book 之间定义 many-to-many relationship
。在Rails中有两种方法可以实现:
选项 1) 使用 has_and_belongs_to_many
根据官方文档has_and_belongs_to_many
协会:
Specifies a many-to-many relationship with another class. This associates two classes via an intermediate join table. Unless the join table is explicitly specified as an option, it is guessed using the lexical order of the class names. So a join between Developer and Project will give the default join table name of “developers_projects” because “D” precedes “P” alphabetically.
因此,您的 类 应该如下所示:
class Bookshelf < ActiveRecord::Base
has_and_belongs_to_many :books
end
class Book < ActiveRecord::Base
has_and_belongs_to_many :bookshelves
has_many :reviews
end
为您的迁移添加一个加入 table 代:
class CreateBooksBookshelvesJoinTable < ActiveRecord::Migration
def change
create_table :books_bookshelves, id: false do |t|
t.belongs_to :book, index: true
t.belongs_to :bookshelf, index: true
end
end
end
这将在您的数据库中创建一个 books_bookshelves
table。 table 将没有主键。您的模型将有两个外键 Book
和 Bookshelf
.
因此,如果您在用户书架的上下文中调用 self.books
,您将获得书架中的图书列表。反之亦然,在一本书的上下文中调用 self.bookshelves
将 return 该书所属的一组书架。
这种方法的问题在于,每次将新书添加到书架时,都会在数据库中创建一条新记录。如果您同意,没有比使用 has_and_belongs_to_many association
更简单的选择了。否则,我建议您选择选项 #2。
选项 2) 使用 has_many :through
另一种选择是使用 has_many, :through association
(see guide)。您将不得不再定义一个模型来执行此操作,但在某些用例中它可能会派上用场(请参见下面的示例)。
您的 类 应该如下所示:
class Bookshelf < ActiveRecord::Base
has_many :books, through: :books_bookshelves
has_many :books_bookshelves
end
class Book < ActiveRecord::Base
has_many :bookshelves, through: :books_bookshelves
has_many :books_bookshelves
has_many :reviews
end
class BooksBookshelf < ActiveRecord::Base
belongs_to :book
belongs_to :bookshelf
end
可能使用 has_many :through association
的最好的事情是它允许您将自定义列添加到连接 table(例如添加列 count
以跟踪有多少本书书架上有相同类型的)。
迁移看起来与我们在选项 1 中使用的迁移几乎相同,除了我们要在外键上添加唯一约束(请注意添加约束是可选的):
class CreateBooksBookshelvesJoinTable < ActiveRecord::Migration
def change
create_table :books_bookshelves, id: false do |t|
t.belongs_to :book, index: true
t.belongs_to :bookshelf, index: true
# add your custom columns here
end
add_index :books_bookshelves, [:book_id, :bookshelf_id], unique: true # to make sure you won't create duplicate records
end
end
通过这种方法,添加新记录会稍微复杂一些,因为您必须确保没有在连接中插入重复记录 table。 (但是,您可以从迁移中删除唯一约束,以实现与使用 has_and_belongs_to_many
时完全相同的行为。)
对于以下情况,您将如何设置 activerecord/datamapper 关联:
一个用户创建了一个 "bookshelf",里面有很多书(一本书 object 只有一个 isbn,用于查询 api,has_many
评论 objects 与之关联)。假设 Jack 用一本书 object 创建了一个 "bookshelf"。然后,假设 Jill 使用同一本书 object 创建了一个 "bookshelf"(它具有相同的 ID 和相同的评论)。本书 object 目前有以下代码:
class Book < ActiveRecord::Base
has_many :reviews
end
然后,当您查看一本书的页面时(从 Jack 创建的 "bookshelf" 单击 link 到它)您应该看到 same book object 当你从 Jill 的 "bookshelf" 点击 link 时(例如 "bookshelves" 都有 link 到 /books/23 因为他们有同一本书 object).
我无法通过 has_many
协会解决这个问题,因为每次用户向他们的 "bookshelf." 添加一本书时,我都需要制作一本新书,我无法理解has_and_belongs_to_many
关系,那是不是应该用在这里?我无法在 SO 上找到任何类似的问题,因此非常感谢您的帮助。
我正在使用 Rails 4 和 Ruby 2.1.
这是一张我想要完成的图: Drawing
是的,您必须在 Bookshelf 和 Book 之间定义 many-to-many relationship
。在Rails中有两种方法可以实现:
选项 1) 使用 has_and_belongs_to_many
根据官方文档has_and_belongs_to_many
协会:
Specifies a many-to-many relationship with another class. This associates two classes via an intermediate join table. Unless the join table is explicitly specified as an option, it is guessed using the lexical order of the class names. So a join between Developer and Project will give the default join table name of “developers_projects” because “D” precedes “P” alphabetically.
因此,您的 类 应该如下所示:
class Bookshelf < ActiveRecord::Base
has_and_belongs_to_many :books
end
class Book < ActiveRecord::Base
has_and_belongs_to_many :bookshelves
has_many :reviews
end
为您的迁移添加一个加入 table 代:
class CreateBooksBookshelvesJoinTable < ActiveRecord::Migration
def change
create_table :books_bookshelves, id: false do |t|
t.belongs_to :book, index: true
t.belongs_to :bookshelf, index: true
end
end
end
这将在您的数据库中创建一个 books_bookshelves
table。 table 将没有主键。您的模型将有两个外键 Book
和 Bookshelf
.
因此,如果您在用户书架的上下文中调用 self.books
,您将获得书架中的图书列表。反之亦然,在一本书的上下文中调用 self.bookshelves
将 return 该书所属的一组书架。
这种方法的问题在于,每次将新书添加到书架时,都会在数据库中创建一条新记录。如果您同意,没有比使用 has_and_belongs_to_many association
更简单的选择了。否则,我建议您选择选项 #2。
选项 2) 使用 has_many :through
另一种选择是使用 has_many, :through association
(see guide)。您将不得不再定义一个模型来执行此操作,但在某些用例中它可能会派上用场(请参见下面的示例)。
您的 类 应该如下所示:
class Bookshelf < ActiveRecord::Base
has_many :books, through: :books_bookshelves
has_many :books_bookshelves
end
class Book < ActiveRecord::Base
has_many :bookshelves, through: :books_bookshelves
has_many :books_bookshelves
has_many :reviews
end
class BooksBookshelf < ActiveRecord::Base
belongs_to :book
belongs_to :bookshelf
end
可能使用 has_many :through association
的最好的事情是它允许您将自定义列添加到连接 table(例如添加列 count
以跟踪有多少本书书架上有相同类型的)。
迁移看起来与我们在选项 1 中使用的迁移几乎相同,除了我们要在外键上添加唯一约束(请注意添加约束是可选的):
class CreateBooksBookshelvesJoinTable < ActiveRecord::Migration
def change
create_table :books_bookshelves, id: false do |t|
t.belongs_to :book, index: true
t.belongs_to :bookshelf, index: true
# add your custom columns here
end
add_index :books_bookshelves, [:book_id, :bookshelf_id], unique: true # to make sure you won't create duplicate records
end
end
通过这种方法,添加新记录会稍微复杂一些,因为您必须确保没有在连接中插入重复记录 table。 (但是,您可以从迁移中删除唯一约束,以实现与使用 has_and_belongs_to_many
时完全相同的行为。)