Rails HABTM加入另一个条件

时间:2011-07-06 21:30:04

标签: ruby-on-rails join has-and-belongs-to-many

我正在尝试获取一个列表,我将以书籍为例。

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?

1 个答案:

答案 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