我正在尝试获取一个列表,我将以书籍为例。
class Book < ActiveRecord::Base
belongs_to :type
has_and_belongs_to_many :genres
end
class Genre < ActiveRecord::Base
has_and_belongs_to_many :books
end
所以在这个例子中我想显示所有类型的列表,但第一列应该是类型。所以,如果说一个类型是“空间”,那么类型可能是“非小说”和“小说”,它会显示:
Type Genre
Fiction Space
Non-fiction Space
Genre表只有“id”,“name”和“description”,连接表genres_books有“genre_id”和“book_id”,Book表有“type_id”和“id”。然而,我无法让它工作。
我知道我需要的sql代码:
SELECT distinct genres.name, books.type_id FROM `genres` INNER JOIN genres_books ON genres.id = genres_books.genre_id INNER JOIN books ON genres_books.book_id = books.id order by genres.name
我发现我可以做到
@genre = Genre.all
@genre.each do |genre|
@type = genre.book.find(:all, :select => 'type_id', :group => 'type_id')
@type.each do |type|
这会让我看到每种类型的类型并将其打印出来,但我无法真正同时使用它们。我认为理想的是,如果在Genre.all声明中我可以以某种方式将它们组合在一起,这样我就可以将类型/类型组合保持在一起并在未来的路上继续使用它们。我试图按照以下方式做点什么:
@genres = Genre.find(:all, :include => :books, :select => 'DISTINCT genres.name, genres.description, books.product_id', :conditions => [Genre.book_id = :books.id, Book.genres.id = :genres.id] )
但是在这一点上,我在圈子里跑来跑去,没有到达任何地方。我是否需要使用has_many:through?
答案 0 :(得分:1)
以下示例使用上面定义的模型。您应该使用范围将关联推送回模型(或者您可以在模型上定义类方法)。这有助于控制记录提取呼叫,并帮助您遵守Demeter法则。
获取图书清单,热切地加载每本图书的类型和类型,无条件:
def Book < ActiveRecord::Base
scope :with_types_and_genres, include(:type, :genres)
end
@books = Book.with_types_and_genres #=> [ * a bunch of book objects * ]
如果你有了这个,如果我理解你的目标,你可以做一些in-Ruby分组,将你的书籍整合到你需要传递给你的视图的结构中。
@books_by_type = @books.group_by { |book| book.type }
# or the same line, more concisely
@books_by_type = @books.group_by &:type
@books_by_type.each_pair do |type, book|
puts "#{book.genre.name} by #{book.author} (#{type.name})"
end