Возвращает массив книг авторов, отношение «многие ко многим»

#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) [] это неудобный способ преобразования an ActiveRecord::Relation в Array использование вместо to_a .

2. Спасибо за комментарии @ngineersmnky, отредактирую свой ответ, чтобы он был более полезным / понятным, хотя я предпочитаю придерживаться подхода arel_table thx 👍