Model z załącznikiem image lub linkiem do video

Witam
Są modele jako STI VideoItem i ImageItem i tabela Items. ImageItem będzie miał obrazek załączony za pomocą Paperclipa i hostowany prawdopodobnie na Amazon S3. VideoItem będzie miał poprostu link do filmiku na youtube, czyli na stonie będzie wyświetlany jako embeded. Pola wspólne to id parenta, tytuł, opis, ilość wyświetleń i takie tam standardowe rzeczy.
Jeśli stosuje STI to w przypadku video zostaje mi w tabeli Items pare pustych pól, których uzywa Paperclip jak image_type, image_size itp. A jeśli dodam kolejny model np ImageAttachement to jest to zawsze jeden model wiecej do wczytywania dla bazy. Kazde z rozwiazan ma plusy i minusy, moze ktos ma lepsze?
Aha, Item ma zawsze tylko jeden obrazek albo video i szacuje stosunek obrazków do video na jakies 70:30 góra 60:40

Myślę, zaznaczam: myślę, że nie potrzebnie się przejmujesz dodatkowymi (i pustymi) kolumnami w tabeli z modelami STI. Tworzenie tabeli z asocjacją 1:1 nie wydaje mi się konieczne - chyba dramatyzujesz ;).

Edit: albo tak jak mówi staszek poniżej, w zależności czy rzeczywiście masz powody do używania tego bydlęcia zwanego STI.

Na Twoim miejscu zrezygnowałbym z STI chociażby ze względu na czytelność takiego rozwiązania. Tabela o nazwie Items może tak naprawdę zawierać wszystko. Proste rozwiązania są najlepsze i jak dla mnie to nie ma sensu tutaj kombinować. 2 modele, 2 tabele i wszystko jest jasne.

Jeszcze jedno. W tabeli videos lepiej chyba, żebyś trzymał tylko numer id filmu z youtuba. Jak zmieni się API albo będziesz chciał coś w przyszłości zakombinować to nie będzie problemu.

Kiedyś podobny problem (jedyna różnica: własny hosting video, więc plik jak najbardziej miał rozmiar i ścieżkę w filesystemie) rozwiązałem, mając modele Image i Video, przez dodanie widoku sql media (który agregował z obu tabel, oczywiście tylko wspólne pola) i modelu AR o nazwie Medium.

hubertlepicki: czym sobie biedne STI zasłużyło na takie określenie ?:slight_smile:

Tylko że tutaj jest taka sprawa, że Itemów może być kilka czy kilkanaście na stronie i to coś jakby lista, bez względu na to czy item zawiera video czy grafikę jest tak samo sortowany itp.
Lista może mieć tylko obrazki albo tylko video ale równie dobrze może być mieszana. Co do pozostałych założeń, jedna strona nie będzie mieć więcej niż kilkananaście itemów (Media) ale ogólnie w skali serwisu będzie duzo obrazków i video, w dziesiątkach tysięcy a mam nadzieje że może i setkach :slight_smile:

Tutaj się zgodzę, przy dodawaniu filmiku można to łatwo wydobyć regexpem. Dodatkowo ten numerek można wykorzystać do wyświetlenia zajawki w formacie jpg którą yt udostepnia na innym serwerze.

Railsy nie mają wtedy problemów z takim widokiem? Jeśli coś zapisywałeś, np. przez formularz to posługiwałeś się normalnie Image albo Video a Medium tylko do odczytu? Zaznaczam że Medium będzie mięc także inne pol jak jakis tytuł, opis, parent_id itd.
A dlaczego nie zastosowałeś tutaj STI skoro byłeś w tej komfortowej sytuacji że modele miały identyczne pola, bo oba hostowane u Ciebie, chyba że nie do końca ?

W przypadku użycia widoku jak szybko jest on aktualizowany, bo napewno chwile zabiera synchronizacja ? W obu tablach tak dziesiątki tysiecy rekordów.
Rails ma jakies wsparcie dla mysqlowych widoków czy poprostu tworzy się zwykły model i na nim operuje ?

  1. Tak, widok oczywiście “read-only”, tworzenie instancji wyłącznie w klasach Image i Video.
  2. Nie są mi znane żadne problemy z aktualizacją/synchronizacją. Nie jest mi znana w ogóle taka możliwość. Nie bez powodu nazywa się to WIDOK :wink:
  3. Nie musi mieć wsparcia, tworzy się zwykły model i jazda

Też kiedyś skorzystałem z widoku (akurat bardzo podobny przypadek do tego co napisał Tomash - też miałem widok/model Medium który pokazywał rekordy z tabel podcasts i videos) do wyświetlenia obiektów różnego typu na jednej stronie.
Kluczem tutaj (niezależnie czy skorzystasz z STI czy z widoku) jest wspólny interfejs dla tych różnych typów, np.

Generujemy widok w migracji:

class CreateMediaView < ActiveRecord::Migration def self.up execute("CREATE VIEW media as " + "SELECT videos.id, videos.title, videos.short_description, videos.long_description, videos.channel_id, videos.fea\ tured, videos.author, videos.viewed, videos.shared, videos.created_at, videos.updated_at, 'Video' as type FROM videos" + "UNION ALL " + "SELECT podcasts.id, podcasts.title, podcasts.short_description, podcasts.long_description, podcasts.channel_id, \ podcasts.featured, podcasts.author, podcasts.viewed, podcasts.shared, podcasts.last_episode_at as created_at, podcasts.update\ d_at, 'Podcast' as type FROM podcasts")
i klasę Medium
(liczba pojedyncza - Medium, liczba mnoga - Media) jest prosta :slight_smile: :

[code=ruby]#####################

This AR class wraps a databse view

run SHOW CREATE VIEW media in the db console to get its structure

#####################

class Medium < ActiveRecord::Base
end[/code]
Ten “wspólny interfejs” to w moim przypadku metody :title, :short_description, :long_description, :channel_id, :featured, :author, :viewed, :shared, :created_at, :updated_at
Oczywiście w widoku możesz sobie pozmieniać nazwy (jeśli kolumny w tablelach nazywają się inaczej ale tak naprawdę można je połączyć w jedną całość w widoku).

Zastosowałem w tym widoku też przekazywanie typu w type. W AR jest konwencja, że jeśli tabela ma kolumnę :type to zadziała STI i otrzymasz obiekt o zadanym typie. Jeśli pominąłbym te fragmenty “Video” as type i “Podcast” as type w powyższym widoku to Medium.all zwróciłoby mi po prostu obiekty klasy Medium a tak mamy Podcast/Video i połączenie widoku z STI.
Dzięki temu mogłem ujednolicić widok (w sensie widoku ERB):

[code=html]


    <% for medium in @media -%>


  • <%= link_to image_tag(medium.thumbnail.file.url(:thumb)), polymorphic_path(medium) if medium.thumbnail -%>
    <%= content_tag :h4, link_to(h(truncate(medium.title, :length => 27)), polymorphic_path(medium)) -%>
    <%= content_tag :p, h(truncate(medium.short_description, :length => 55)) -%>


  • <% end -%>
[/code] Efekt można zobaczyć [url=http://www.play.mdx.ac.uk/channels?page=3]tutaj[/url] (Strength and conditioning to "Podcast" reszta to "Video") Oczywiście nie jest to jedyne rozwiązanie tego problemu ale myślę, że całkiem fajnie działa (i wygląda w sensie ujednoliconego kodu widoku).

Warto jeszcze wspomnieć, że jeśli korzystamy z widoków w Railsach to dobrze jest użyć gemu rails_sql_views Możemy wtedy

  1. w migracji utworzyć widok za pomocą “create_view” a nie tak jak ja zrobiłem za pomocą “execute” oraz
  2. Schema dumper zrzuca widok do schema.rb (railsowe rake db:schema:dump zrzuca tylko tabele) więc jeśli piszemy testy w aplikacji to rake db:test:clone_structure skopiuje nam również schemat widoku do testowej bazy - bardzo przydatna rzecz).

hosiawak: Wielkie dzięki za wyczerpujący przykład i wyjaśnienia. Polymorphic path też się przyda widzę.
Co do typu to w jakiejś książce pisało żeby nie używać ‘type’ do STI bo coś innego tego używa i mogą być problemy, lepiej np ‘media_type’, nie pamietam niestety gdzie i dlaczego.
Zastanawiam się też czy w przypadku widoku nie będzie problemów przy zaimplementowaniu np. ilości wyświetleń danego medium, jeśli są one w osobnych tabelach, wtedy użycie samego id nie wystarczyło by. Sortowanie np. po ilości oglądnieć nie powinno być problemem bo wtedy moge w widoku po tym posortować.

Stary, przestań się martwić i zastanawiać, tylko implementuj i zobacz jak działa :slight_smile:

Tak będzie trzeba chyba zrobić, bo cieżko przewidzieć wszystko możliwości i ewentualne pułapki :slight_smile:

@Artur79: Jest dokładnie na odwrót z tą kolumną “type”: Nie powinno się używać kolumny o nazwie “type” do czegoś co nie jest AR’owym STI. Czyli jeśli chcesz sobie dodać typ obiektu i nazwać go “type” ale nie chcesz korzystać z “dobrodziejstw” STI tylko zaimplementować swoje rozwiązanie to NIE TWORZYSZ KOLUMNY O NAZWIE “type” :slight_smile: (nazywasz ją np. user_type, media_type etc.)

Ilość wyświetleń wrzucasz do tego “wspólnego interfejsu”, np. kolumna :viewed zarówno w tabeli podcasts jak i videos (w moim przypadku) oraz w widoku - i możesz sobie dowolnie sortować po czym chcesz, stronicować (will_paginate) itd.

Spoko, sory za zamieszanie.
A co z modelami powiązanymi z media np. class Medium has_many :comments. Np. dodaje coś w Podcasts, mysql mi ładnie aktualizuje view Media ale czy zachowane są id tych medium które już tam były a co za tym idzie przypisane komentarze (przy użyciu np. acts_as_commentable) ? Albo co gdy coś usunę. Chyba że wtedy nie Medium a Podcast i Video, oba muszą mieć has_many :comments albo acts_as_commentable.
W tym przykładowym widoku z Union, id będą powielone często, domyślam się.