I have a model say Book
which has the following scope function:
scope :author, lambda { |author|
return where(nil) unless author.present?
joins(:author).where('author.id' => author)
}
This can filter the Books with only ONE author value. What I want to do is that I am passed a array from a JavaScript file which is a list of authors for example: ["harry", "doyle", "alex", "parrish"]
and I want to be able to find all the books who has ANY of these authors (so an OR query here). Note each book can have multiple authors.
I have tried the following function but it simply gives me all the books rather than filtering correctly as I stated above.
scope :authors_multiple, lambda { |authors|
@results = Book
authors.each do |auth|
@results = @results.author(auth)
end
return @results
}
model Author (extract):
class Author < ApplicationRecord
has_and_belongs_to_many :books, uniq: true
....
model Book (extract):
class Book < ApplicationRecord
has_and_belongs_to_many :authors, uniq: true
....
Can you please help me understand what I am doing wrong or what may be the right way to do it. Thanks in advance.
authors = ["harry", "doyle", "alex", "parrish"]
Book.where(author: authors)
or
authors = ["harry", "doyle", "alex", "parrish"]
auths = Author.where(name: authors)
Book.where(author: auths)
This assumes that an Author has many Books. You can learn more about model associations here: https://guides.rubyonrails.org/association_basics.html
First you need to get your Author
records. How this is done depends on your schema and data, but it will be something akin to:
author_names = ["harry", "doyle", "alex", "parrish"]
Then one of the following:
authors = Author.where(name: author_names)
authors = Author.where("name ILIKE ANY ( array[?] )", author_names.map { |name| "%#{name}%" })
Something that gets us an ActiveRecord::Relation
of the authors we need. Once we have the authors we can merge that with our books to get all the books we want:
books = Book.joins(:authors).merge(authors)
Note that the join is on the plural author s . Rails will know to join through the join table (should be authors_books
by default) to the authors
table.
You get an array of author names, right?
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?
}
It should work properly with array or string argument
Book.by_author(["harry", "doyle"])
Book.by_author("harry")
Try Below code:
authors = ["harry", "doyle", "alex", "parrish"]
Book.joins(:authors).where(:authors => {:name => authors})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.