2015-09-04 2 views
3

Итак, у меня есть следующие модели:Все полиморфные модели одного типа?

class Favorite < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :favoritable, polymorphic: true 
    # Table has a favoritable_id and favoritable_type 
end 

class Book < ActiveRecord::Base 
    has_many :favorites, as: :favoritable 
end 

class Magazine < ActiveBoard::Base 
    has_many :favorites, as: :favoritable 
end 

class User < ActiveRecord::Base 
    has_many :favorites 
end 

Когда я делаю вызов:

user = User.find(1) 
user.favorites 

Это возвращает все избранные книги и журналы, как и ожидалось (в основном то, что это выглядит как в базе данных с favoritable_id и favoritable_type столбцы/свойства). Когда я называю это:

user = User.find(1) 
user.favorites.books 

Я получаю сообщение об ошибке, которая говорит:

NoMethodError: undefined method 'books' ... 

Однако, позвонив:

user = User.find(1) 
user.favorites.first.favoritable 

Это прекрасно работает.

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

Еще раз спасибо.

ответ

4

ли так:

user.favorites.map {|f| f.favoritable} 

Или, чтобы получить только любимые книги, сделать это:

user.favorites.select { |f| f.favoritable_type == 'book' }.map { |f| f.favoritable } 
+0

Хорошо, это работает, но возвращает все модели любимых (все журналы и книги). Как я могу получить только книги? – Sean

+0

попробуйте обновленный ответ. –

+0

Хорошо, это работает, но возвращает все модели любимых (все журналы и книги). Как я могу получить только книги? – Sean

1

Вы можете легко определить соотношение между User и Book с и Magazine с использованием кода ниже:

class User < ActiveRecord::Base 
    has_many :favorites 
    has_many :favorite_books, through: :favorites, source: :favoritable, source_type: 'Book' 
    has_many :favorite_magazines, through: :favorites, source: :favoritable, source_type: 'Magazine' 
end 

Теперь вы можете легко книги и журналы LY запроса пользователя в:

user.favorite_books 
user.favorite_magazines 

Книги запрос производит следующий SQL:

SELECT "books".* FROM "books" 
INNER JOIN "favorites" ON "books"."id" = "favorites"."favoritable_id" 
WHERE "favorites"."user_id" = ? AND 
     "favorites"."favoritable_type" = ? 
     [["user_id", 1], ["favoritable_type", "Book"]] 

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

Еще одно преимущество этого подхода заключается в том, что он хорошо масштабируется. Например, если вы хотите знать, какие книги Жюля Верна добавляются в избранное данным пользователем, это очень естественно для запроса:

user.favorite_books.where('books.author = ?', 'Jules Verne') 
+0

@KMRakibulIslam, дающий ответ «достаточно», не так, как должно быть сделано. Я думаю, мы все должны стремиться к лучшим и даже лучшим ответам. Если вы можете показать мне лучший способ решить проблему, я буду очень рад узнать вас. – dimakura

+0

@dimakura Мне очень нравится ваше решение.Однако, как бы это сделать, если я все еще хочу, чтобы это выглядело? users.favorites.books? или users.favorites.magazines? Возможно ли это? Или другое решение ... users.favorite_books? Я новичок в Rails, так что простите меня по этому поводу ... – Sean

+0

@Sean, users.favorites.books невозможно. Но user.favorite_books достижимо. Я обновил свой ответ соответственно (для журналов тоже). – dimakura

Смежные вопросы