Reputation: 6179
Imagine a Book and a Chapter model. Each Chapter belongs_to :book
, and a Book has_many :chapters
. We have scopes on the Chapter, for example :very_long
returns chapters with over 300 pages.
Many times we want to get all books with any chapters over 300 pages. The way we usually achieve this is like so:
# book.rb
scope :has_very_long_chapter, -> { where(id: Chapter.very_long.select(:book_id) }
However, as you can imagine, it gets pretty tedious to proxy the scope every time we want to filter Books by chapter scopes. Is there any more idiomatic or cleaner way to achieve this?
Upvotes: 2
Views: 1920
Reputation: 111
To get those books you can use ActiveRecord::SpawnMethods#merge
, and you don't have to use another scope:
Book.joins(:chapters).merge(Chapter.very_long)
Upvotes: 1
Reputation: 983
I think one thing you could do would be to use joins/merge
class Book < ARBase
scope :with_long_chapters, ->{ joins(:chapter).merge(Chapter.very_long) }
end
class Chapter < ARBase
scope :very_long, -> { logic for querying chapters with over 300 pages }
end
EDIT(#2): A more reusable scope
class Book < ARBase
scope :by_chapter_page_count, ->(pages){ joins(:chapter).merge(Chapter.by_page_count pages) }
scope :with_climax, -> { joins(:chapter).merge(Chapter.by_category :climax) }
scope :long_with_climax, -> { by_chapter_page_count(400).with_climax }
end
class Chapter < ARBase
scope :by_page_count, ->(pages) { where("pages > ?", pages }
scope :by_category, ->(category) { where category: category }
end
Book.by_chapter_page_count(100)
You can get fairly creative with how you write your scopes
Upvotes: 0