2017-02-09 2 views
2

Представьте себе книгу и модель главы. Каждая глава belongs_to :book и книга has_many :chapters. У нас есть области действия в главе, например, :very_long возвращает главы с более чем 300 страницами.Rails scope on association_to association

Много раз мы хотим получить все книги с любыми главами более 300 страниц. То, как мы обычно достигают это примерно так:

# book.rb 
scope :has_very_long_chapter, -> { where(id: Chapter.very_long.select(:book_id) } 

Однако, как вы можете себе представить, это становится довольно утомительно прокси сферу каждый раз, когда мы хотим, чтобы отфильтровать книги по главе областей. Есть ли более идиоматический или более чистый способ достичь этого?

ответ

-1

Я думаю, что одна вещь, которую вы могли бы сделать, чтобы использовать 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): более многоразовый объем

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) 

Вы можете получить достаточно творчески, как вы пишете scopes

+1

Это немного чище, но это не решает проблему необходимости писать новую область каждый раз, когда я хочу повторно использовать ее на дочерней модели. – jtmarmon

+0

@jtmarmon вы могли бы прояснить, что вы имеете в виду, создавая новую область каждый раз, когда хотите повторно использовать одно из дочерней модели? Я не совсем уверен, что понимаю, к чему вы клоните. Если вы хотите иметь другой запрос, вам нужно будет определить новые области. – Sean

+0

@jtmarmon Позвольте немного пересмотреть мой ответ, чтобы увидеть, можно ли сделать область более пригодной для повторного использования. – Sean

1

Чтобы получить эти книги, вы можете использовать ActiveRecord::SpawnMethods#merge, и вам не нужно использовать другую область:

Book.joins(:chapters).merge(Chapter.very_long) 
Смежные вопросы