#ruby-on-rails #many-to-many
#ruby-on-rails #многие ко многим
Вопрос:
У меня есть две модели: Author и Book и промежуточная таблица middleItem. Существует связь «многие ко многим». Моя задача — создать переменную @MyBooks, которая возвращает массив всех книг, которые есть у автора. Однако мы будем искать по идентификатору автора в сеансе session[:user_id]
class middleItem < ApplicationRecord
belongs_to :author
belongs_to :book
end
class Book < ApplicationRecord
has_many :middleItem
has_many :author, through: :middleItem
end
class Author < ApplicationRecord
has_many :middleItem
has_many :books, through: :middleItem
end
Однако это не работает
Book.joins(:authors).joins(:middleItem).where(middleItem: {user_id: session[:user_id]}).distinct.map {|x| puts x.name}
Редактировать:
Авторы: (1) Шекспир, (2) Оруэлл
Книги: (1) Ромео и Джульетта, (2) Гамлет, (3) Скотный двор
Средняя таблица: (1,1), (1,2), (2,3)
@MyBooks должно быть: «ромео и Джульетта, гамлет», если, допустим, session[:user_id] равно 1
Комментарии:
1. ну, помимо запроса, который требует некоторой работы, я думаю, у вас есть опечатка в вашей книжной модели, в ней должно быть написано: авторы
2. Не уверен, что я понимаю некоторые части для этого, но, основываясь исключительно на вашем коде
Book.joins(:authors).where(authors: {id: session[:user_id]})
, должно быть достаточно. Примечание:map {|x| x.any_db_attribute_here}
всегда можно сократить доpluck(:any_db_attribute_here)
3. Спасибо за вашу помощь. Я попытался прояснить ситуацию, проверьте редактирование
4. @engineersmnky Это работает идеально, спасибо!
Ответ №1:
Я думаю, что для решения этой проблемы хорошо подходит использование scopes
, вы можете определить область действия в своей book
модели, как показано ниже:
scope :search_by_author, ->(author_id) { joins(:authors).where(Author.arel_table[:id].eq(author_id)).distinct}
Приведенное выше можно использовать следующим образом: Book.search_by_author(1)
и если вам действительно нужен массив вместо результата ActiveRecord, вы можете преобразовать результат в массив : Book.search_by_author(1).to_a
.
Надеюсь, что вышесказанное поможет! 👌
Комментарии:
1. Несколько конструктивных комментариев: 1) Вы можете использовать
Author.arel_attribute(:id)
вместоAuthor.arel_table[:id]
; 2) для простых случаев использования, таких как равенствоwhere(table_name: { column_name: value})
, обычно считается более идиоматичным, чем использованиеArel
; 3)[]
это неудобный способ преобразования anActiveRecord::Relation
вArray
использование вместоto_a
.2. Спасибо за комментарии @ngineersmnky, отредактирую свой ответ, чтобы он был более полезным / понятным, хотя я предпочитаю придерживаться подхода arel_table thx 👍