Zapisywanie załączników różnych typów (pdf, jpg, doc, itd)

Chcę stworzyć aplikację, która m.in. ma przechowywać załączniki różnych typów (jpg, pdf, doc) związane z określonym rekordem modelu - powiedzmy - Car.

Jak Waszym zdaniem należy zabrać się za to?

Myślałem, by stworzyć model jeden_do_wielu (myfile) z załącznikami i dołożyć obsługę zapisywania plików np paperclip.

Wyświetlać to później jakoś

car.myfiles.each  do |f|
.... 

end

i w zależności od typu pliku wyświetlać ikonę odpowiednią do typu pliku, która będzie linkiem do niego.

Wiem, że nie jest to zadanie typu “wysyłanie człowieka na księżyc” ale chciałbym wiedzieć, jak robią to profesjonaliści. :wink:
Jakich rozwiązań i jakich gemów używają.

Znalazłem przykłady z paperclip, z refile, z zapisywaniem też do bazy, itd.

Co DZISIAJ powinno nam przyświecać przy implementowaniu takiej funkcjonalności?

I to jest bardzo dobry pomysł, biorąc pod uwagę opis problemu.

Dzięki za potwierdzenie słuszności koncepcji.

Ma ktoś może jakieś rady, co do przechowywania tych załączników?

  • katalog z plikami vs baza danych

Będą to raczej małe pliki - do 300k max.
Wydaje się bardzo fajnym pomysłem umieszczanie tego w bazie (Postgres), ale mam wątpliwości.
Ktoś z Was ma może doświadczenie z taką bazą, w której znajduje się ok 70-80 tys takich załączników?

80k załączników po 300kb średnio powinno dać jakieś 30GB w bazie danych, postgres poradzi sobie z tym bez najmniejszej trudności, pamiętaj jedynie żeby ustawić pole na typ binary.

:smile:

O tym typie (binary) wiem i pamiętam, ale dzięki.

A co Ty byś wybrał?
Stary, sprawdzony sposób ze składnicą plików w jakimś folderze, czy przechowywanie w bazie?

Gwoli informacji dodam, że 99,9 % operacji związanych z tymi załącznikami, to będzie dodanie załącznika (raczej jednego) raz i “na zawsze”. Do wyjątkowych sytuacji będzie należało zmienianie go na inny bądź dokładanie po czasie kolejnych, związanych z danym rekordem.

Pamiętaj, że odczyt bezpośrednio z systemu plików jest zawsze szybszy od odczytu z bazy danych. Przechowywanie w bazie danych ma większy sens w momencie kiedy chcesz indeksować zawartość tych plików. Trzymanie plików w bazie tylko po to by były w bazie nie ma chyba większego sensu.

Ja pliki trzymam na S3.

Nie wiem, co masz na myśli pisząc “chcesz indeksować zawartość tych plików”.
Czy chodzi Tobie o “otagowanie” ich i późniejsze wyszukiwanie załączników spełniających określone kryteria?


Mam do zrobienia apkę, która ma m.in wyświetlić dane jakiegoś rekordu i jeżeli ten rekord ma dołączony załącznik “jpg”, to elegancko wyświetlić go.
Nic więcej i nic bardziej wyrafinowanego.

Twoja uwaga dotycząca szybkości odczytu jest cenna i kto wie, czy nie będzie najważniejszym kryterium przy podejmowaniu decyzji.

Indeksowanie zawartości w celu np. wyszukiwania w treści tych plików. Ale po namyśle wydaje mi się że i tak same pliki bym wrzucił na s3 a do indeksowania zawartości inaczej bym się zabrał, chociażby dlatego że to nie są pliki tekstowe tylko różnego rodzaju binarki. A tagowanie to zupełnie inną sprawą. Do tego na pewno nie ma najmniejszej potrzeby trzymać pliki w bazie.

Dzięki za uwagi i sugestie.

Masz gdzieś benchmarki do tego kolego? Bo jak nie to uważaj z tego typu uwagami, bo możesz się przejechać. Różnicy w szybkości dostępu nie powinno być żadnej (jedyny przypadek to jeśli ustawiłbyś to tak że Nginx serwuje pliki bezpośrednio z dysku z użyciem DMA prosto dysk -> sieć, wtedy będzie odrobinę szybciej),

Nie widzę najmniejszego sensu w trzymaniu tego typu plików na S3 - dodajesz tylko kolejny stopień złozoności beż żadnych benefitów (bo zakłądam że nie tworzysz aplikacji która będzie rozproszona z instancjami na kilku kontynentach, i odwiedzana często z różnych stron świata co jest głowną zaletą S3).

Ja osobiście wrzucałbym pliki do bazy danych jeżeli w przyszłości planujesz więcej niż jedną instancję aplikacji korzystającą z tych samych plików, a na dysku w innym wypadku,

Dobra, może z tą prędkością odczytu przesadziłem, bo to wszystko zależy od ustawień samej bazy oraz serwera.

Nadal, jeżeli to ma być nawet niewielka aplikacja to bym obstawał za S3. Nie muszę się wtedy przejmować tak naprawdę niczym związanym z przechowywaniem tych plików, a w bazie trzymam tylko link do pliku i ew. refrencje do starszych wersji. Nie muszę się przejmować backupem plików, a sama baza będzie też zajmować o wiele mniej niż gdyby miała w sobie mieścić wszystkie te dokumenty.

Być może to są argumenty na siłę, ale wolę mieć mniejszą bazę z “dokumentami” gdzieś w bezpiecznym miejscu, niż “dokumenty” w bazie i bazę liczoną w dziesiątkach gigabajtów. Zwłaszcza że trzymanie danych na s3 jest trywialne dzięki np. https://github.com/markevans/dragonfly-s3_data_store

A jak będziesz serwować pliki trzymane w bazie? Bez jakiegoś dynamicznego rozwiązania (ruby/php/whatever) nie obędzie się, prawda? Nginx wyciąga na średnio nowoczesnej maszynie na luzie 10 tys. req/s. Wyciągnięcie tylu requestów w sposób dynamiczny już takie proste nie jest.

Ja to widzę tak. Trzymanie plików w bazie (chociaż nigdy tego nie robiłem) rozwiązuje problemów współdzielenia plików przez wiele serwerów (taki współdzielony storage). Zatem:

  1. Jeśli nie spodziewasz się zawału requestów po pliki tych załączników i masz wiele serwerów (z których wrzucasz pliki) to trzymanie w bazie tych plików powinno być ok.
  2. Jeśli spodziewasz się ogromnego ruchu to rozwiązanie z nginxem jest spoko.
  3. Jeśli masz 1 serwer i nie spodziewasz się wielkiego ruchu to oba rozwiązania są ok.
  4. Jeśli spodziewasz się ogromnego ruchu i masz wiele serwerów to połączenie tych rozwiązać byłoby ok (nginx jako reverse proxy cache, a backend serwuje plik z bazy).

Przeczytaj jeszcze raz co napisałem w ostatnim poście, trzymanie plików w bazie danych rzeczywiscie ma sens tylko jeśli zechcesz w przyszłości wspóldzielić te pliki między aplikacjami na róznych serwerach w gruncie rzeczy.

Co do serwowania dynamicznego, to w większości przypadków tak czy tak obsługa wysyłki plików musi prejść przez railsy ze względu na kontrolę dostępu chociażby. Co prawda X-Sendfile w tym wypadku powinien być użyty tak czy tak.

Anyway. Podsumowując:

  1. Trzymaj pliki na dysku o ile nie ma innych wymagań/przeciwskazań
  2. S3 jeżeli nie ma przeciwskazań (np. pliki z danymi osobowymi)
  3. Baza danych

W tej kolejności mniej więcej :slight_smile:

Dziękuję Wam za te wszystkie uwagi. Są one dla mnie bardzo cenne.

Muszę jednak rzucić trochę więcej informacji o tej przyszłej apce i środowisku.

Aplikacja ma działać wewnątrz sieci WAN. (Nawet nie w DMZ’ecie tylko “w środku”)
Ruch będzie niewielki (na początku) ale firma ma fobię na punkcie ochrony danych i żadne składowanie załączników na zewnątrz ich infrastruktury nie wchodzi w grę.

Dzisiaj te załączniki są rozrzucone po kilku udostępnianych folderach i szukanie odpowiedniej informacji jest makabrą.
Mają postać np. VIN123456 Opel Astra.jpg

Mam to uporządkować.
Pragnę więc stworzyć aplikację, która zaimportuje dane o (powiedzmy) numerach VIN i modelach pojazdów z bazy danych, która ma te wszystkie numerki i modele zapisane, a następnie użytkownik (po wyszukaniu po np numerze) zobaczy w formularzu “show” te załączniki i nie będzie musiał przeszukiwać kliku folderów (i kilkudziesięciu podkatalogów :open_mouth: )

Mam dylemat, czy aplikacja winna:
A) “wciągnąć” te załączniki do bazy
B) “wciągnąć” do nowo utworzonej składnicy plików zarządzanej moją apką
(dla wariantów A i B stara “składnica” leci w kosmos),
C) czy ma przechowywać tylko linki do plików, a ludzie nadal mają “kontynuować swoje dzieło”

Póki co jestem za wariantem A lub B, ze wskazaniem na A :wink:

Mam do dyspozycji macierze dyskowe, maszyny wirtualne i mogę zbudować środowisko jakie uznam za stosowne.

Mówiąc krótko - mam całkowicie wolną rękę i chciałbym to zrobić DOBRZE, patrząc trochę w przyszłość.
A patrząc w przyszłość, to widzę, że “jutro” z tych danych będzie korzystać coraz więcej działów w tej firmie, a kto wie, czy nie powstaną inne aplikacje, które będą chciały współdziałać z tą “moją składnicą”.

Co do samej bazy, to też mogę zrobić, co uważam za stosowne.
Mam co prawda doświadczenie z clustrami MariaDB i MySQL, ale chcę odchodzić od tego silnika.
Po 1,5 roku pracy z Postgresem widzę coraz więcej rzeczy przemawiających na korzyść tego silnika i sądzę, że i Postgress pozwoli zbudować coś “Scalability and High Availability”, zatem Wasze uwagi o przechowywaniu tych załączników w bazie traktuję bardzo poważnie.

Napisałem system obiegu dokumentów działający w kilku dużych instytucjach na załozeniach jak Twoje i tam uzyłem carrierwave + carrierwave-postgresql. Doradzam jako storage bd z innego powodu o jakim nie wspomnieliście, późniejsze problemy i kontrola nad wykonywaniem kopii.