Załóżmy, że nasza aplikacja ma model MediaObject, który posiada tytuł, głosy itd. ale specyficzne informacje n/t obiektu (treść/link etc.) są w innym modelu (Media::Text, Media::Image etc.). Relacja oczywiście jeden-do-jeden. Jeżeli zrobimy to na zasadzie referenced assosiation, czyli relacje rodem z baz SQL, będziemy mieli zawsze n+1 zapytań. Mongoid co prawda obsługuje eager loading, ale nie dla relacji polimorficznych. Co więc możemy zrobić?
Tworzymy model MediaObject:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /app/models/media_object.rb | |
class MediaObject | |
include Mongoid::Document | |
embeds_one :resource, class_name: 'Media::Resource' | |
field :title, type: String | |
end |
Oraz model Media::Resource - po nim będą dziedziczyć wszystkie modele z modułu Media
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /app/models/media/resource.rb | |
class Media::Resource | |
include Mongoid::Document | |
embedded_in :media_object | |
end |
Teraz możemy dodać np. model Media::Text
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /app/models/media/text.rb | |
class Media::Text < Media::Resource | |
field :content, type: String | |
end |
Użycie:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
media_object = MediaObject.new(title: "This is title") | |
media_object.resource = Media::Text.new(content: 'This is content') | |
media_object.save |
Żeby ułatwić sobie życie, możemy wydelegować #content do MediaObject
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /app/models/media_object.rb | |
class MediaObject | |
include Mongoid::Document | |
embeds_one :resource, class_name: 'Media::Resource' | |
field :title, type: String | |
delegate :content, to: :resource, allow_nil: true | |
end |
Opcja allow_nil pozwala trzymać w #content pustą wartość. W tym przypadku to bardzo ważne, bo nie wiemy czy napewno wszystkie modele Media będą miały taką metodę. Gdyby nie miały, bez tej opcji model zawrze rzucał by wyjątek. Teraz użycie wygląda tak:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
media_object = MediaObject.first | |
puts media_object.content | |
# zamiast: | |
media_object = MediaObject.first | |
puts media_object.resource.content |
Brak komentarzy:
Prześlij komentarz