has_and_belongs_to_many
фактически не использует модель соединения. То, что вы ищете, это has_many through:
class User < ApplicationRecord
has_many :book_users
has_many :books, through: :book_users
end
class Book < ApplicationRecord
has_many :book_users
has_many :users, through: :book_users
end
class BookUser < ApplicationRecord
belongs_to :book
belongs_to :user
end
Если вы хотите добавить категории в книги, вы бы сделали это, добавив модель категории и другую таблицу соединений. Не создавая модель Fiction
, которая просто создаст сумасшедший объем дублирования кода, если вам нужно несколько категорий.
class Book < ApplicationRecord
has_many :book_users
has_many :users, through: :book_users
has_many :book_categories
has_many :categories, through: :book_categories
end
class BookCategory < ApplicationRecord
belongs_to :book
belongs_to :category
end
class Category < ApplicationRecord
has_many :book_categories
has_many :books, through: :book_categories
end
Если вы хотите запрашивать пользователей, которые следуют определенной книге, вы можете сделать это с помощью используя внутреннее объединение с условием для книг:
User.joins(:books)
.where(books: { title: 'Lord Of The Rings' })
Если вы хотите получить книги определенной категории:
Book.joins(:categories)
.where(categories: { name: 'Fiction' })
Тогда для финала - запросить пользователей с помощью отношение по крайней мере к одной книге, которая относится к категории «Художественная литература», которую вы бы сделали:
User.joins(books: :categories)
.where(categories: { name: 'Fiction' })
# or if you have an id
User.joins(books: :categories)
.where(categories: { id: params[:category_id] })
Вы также можете добавить косвенную связь, которая позволит вам go переходить от категории к пользователям:
class Category < ApplicationRecord
# ...
has_many :users, though: :books
end
category = Category.includes(:users)
.find(params[:id])
users = category.users
См .: