Как отфильтровать поле модели по нескольким значениям (OR'd) - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть модель, скажем Book, которая имеет следующую функцию объема:

scope :author, lambda { |author|
    return where(nil) unless author.present?
    joins(:author).where('author.id' => author)
  }

Это может фильтровать Книги только с одним значением автора.Я хочу, чтобы мне передали массив из файла JavaScript, который представляет собой список авторов, например: ["harry", "doyle", "alex", "parrish"], и я хочу иметь возможность найти все книги, которые ЛЮБЫЕ из этих авторов (поэтому запрос ИЛИВот).Обратите внимание, что у каждой книги может быть несколько авторов.

Я попробовал следующую функцию, но она просто дает мне все книги вместо того, чтобы правильно фильтровать, как я уже говорил выше.

scope :authors_multiple, lambda { |authors|
  @results = Book
  authors.each do |auth|
    @results = @results.author(auth)
  end
  return @results
}

модель Автор (извлечение)):

class Author < ApplicationRecord
  has_and_belongs_to_many :books, uniq: true
  ....

модель Книга (выдержка):

class Book < ApplicationRecord
  has_and_belongs_to_many :authors, uniq: true
  ....

Не могли бы вы помочь мне понять, что я делаю неправильно или что может быть правильным способом сделать это.Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 28 февраля 2019

Попробуйте ниже код:

authors = ["harry", "doyle", "alex", "parrish"]    
Book.joins(:authors).where(:authors => {:name => authors})
0 голосов
/ 28 февраля 2019

Сначала вам нужно получить ваши Author записи.Как это сделать, зависит от вашей схемы и данных, но это будет что-то вроде:

author_names = ["harry", "doyle", "alex", "parrish"]

Тогда одно из следующего:

authors = Author.where(name: author_names)
authors = Author.where("name ILIKE ANY ( array[?] )", author_names.map { |name| "%#{name}%" })

Что-то, что дает нам ActiveRecord::Relation авторов нам нужны.Когда у нас есть авторы, мы можем объединить их с нашими книгами, чтобы получить все нужные нам книги:

books = Book.joins(:authors).merge(authors)

Обратите внимание, что объединение принадлежит множественному автору s .Rails будет знать, как присоединиться через таблицу соединения (по умолчанию authors_books) к таблице authors.

0 голосов
/ 28 февраля 2019

Вы получаете массив имен авторов, верно?

scope :by_author, lambda { |names|
  # if you have a chance to get blank values you need to reject them
  names.reject!(&:blank?) if names.is_a? Array

  joins(:authors).where(authors: { name: names }).distinct if names.present?
}

Он должен правильно работать с аргументом массива или строки

Book.by_author(["harry", "doyle"])
Book.by_author("harry")
0 голосов
/ 28 февраля 2019
authors = ["harry", "doyle", "alex", "parrish"]  
Book.where(author: authors)

или

authors = ["harry", "doyle", "alex", "parrish"]  
auths = Author.where(name: authors)
Book.where(author: auths)

Предполагается, что у автора много книг.Вы можете узнать больше о модельных ассоциациях здесь: https://guides.rubyonrails.org/association_basics.html

...