Рельсы HABTM соединяются с другим условием - PullRequest
0 голосов
/ 07 июля 2011

Я пытаюсь получить список, и я буду использовать книги в качестве примера.

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

Так что в этом примере я хочу показать список всех жанров, но в первом столбце должен бытьтип.Таким образом, если сказать, что жанр «Space», типы могут быть «Non-fiction» и «Fiction», и он будет отображать:

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 Ответ

1 голос
/ 07 июля 2011

В следующих примерах используются ваши модели, определенные выше. Вы должны использовать области, чтобы вернуть ассоциации обратно в модель (в качестве альтернативы вы можете просто определить методы класса в модели). Это помогает контролировать ваши звонки и помогает вам придерживаться закона Деметры.

Получите список книг, загружая тип и жанр каждой книги без условий:

def Book < ActiveRecord::Base
  scope :with_types_and_genres, include(:type, :genres)
end

@books = Book.with_types_and_genres  #=> [ * a bunch of book objects * ]

Если у вас есть это, если я понимаю вашу цель, вы можете просто сделать несколько группировок в 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
...