Upload plików to teoretycznie prosta sprawa, wystarczy input w htmlu. Ale musimy te pliki gdzieś zapisać. W ruby on rails na pomoc przychodzi Active Storage. Dzięki niemu możemy dołączać pliki do naszych obiektów active recorda. Pliki te możemy przetrzymywać w chmurze np amazon s3 czy azure storage od microsoftu. Korzystając z Active Storage. Po przesłaniu pliku graficznego możemy konwertować je do innych formatów. Ale też robić dużo innych czynności nie tylko związanych z obrazkami.

jeżeli chcecie używać active storage najpierw trzeba dodać go do naszej aplikacji

rails active_storage:install

utworzy to między innymi wcześniej wspomniane tabele

następnie trzeb uruchomić migrację

rails db:migrate

w pliku config/storage.yml

możemy ustawić różnych providerów do trzymania danych, nie musimy się ograczniać do jednego. Możemy dane trzymać zarówno na dysku jak i np na s3. Możemy też wybierać providera zależnie od tego gdzie nasza aplikacja jest uruchomiona, np na produkcji używać s3 a lokalnie czy przy testach dysku.

na chwile obecną wystarczy nam dysk

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

do providerów jeszcze wrócę

Jeżeli zastanawiacie się po co trzymać pliki po za serwerem już spieszę z odpowiedzią.

  • po pierwsze na heroku które najczęsciej tu pokazuje pliki kasują się z każdym deploymentem. Więc o ile nie są to pliki tymczasowe musicie trzymać je po za heroku
  • po drugie - skalowanie. Jeżeli chcecie mieć odpaloną maszynę na kilku urządzeniach, pliki muszą być w jednym miejscu
  • po trzecie - cena to chyba w tym momencie bardzo istotne, usługi do trzymania plików są bardzo tanie. Jeżeli weźmiemy jakiegoś vpsa np digitalocen to owszem wraz z wzrostem ceny rośnie też dostępne miejsce, ale często rośnie nam zapotrzebowanie na miejsce, nie na resztę zasobów. Po co płacić za 16gb ram jeżeli wykorzystujemy tylko 2gb? Po za tym na przykładzie digitalocean, za 80$ na miesiąc mamy tylko 320GB . Dla porównania na tym samym digitalocean dostępna jest usługa spaces. Gdzie 250gb kosztuje tylko 5$. Dodatkowo takie usługi płatne są tylko za miejsce które wykorzystujecie. No i transfer.

To chyba najważniejsze. Ostatecznie jest taniej, szybciej i bezpieczniej. Ale jeżeli używacie innej usługi niż heroku (np jakiegoś vpsa) oraz nie planujecie trzymać wielu plików, nic nie stoi na przeszkodzie by trzymać te pliki lokalnie czyli na dysku

Nie zależnie co wybierzecie jako miejsce trzymania plików reszta konfiguracji wygląda podobnie.

Pora zacząć trzymać jakieś pliki. Wykorzystam tu kod z jednego z wcześniejszych filmów.

do modelu Post dodajmy has_one_attached :cover_image

doda to załącznik do modelu, i relacje do wcześniej utworzonej tabeli. Ponieważ nie ważne ile modeli z załącznikami będziemy mieć. Wszystkie informacje o nich będą trzymane właśnie we wcześniej utworzonej tabeli.

w widoku formularza od naszego posta dodajmy

	<div class="field">
    <%= form.label "Obrazek" %>
    <%= form.file_field :cover_image %>
  </div>

musimy jeszcze w kontrolerze zaaakceptować nowy parametr

def post_params
  params.require(:post).permit(:title, :body, :category_id, :cover_image)
end

skoro mamy już obrazek to jeszcze trzeba go wyświetlić

przejdźmy do widoku naszego posta

dodajmy <%= image_tag @post.cover_image %>

railsy mają helper image_tag który odpowiada za wyświetlanie obrazków

to tyle jeżeli chodzi o obrazki

ale teraz gdzieś musimy je trzymać. Lokalnie nie ma problemu - dysk. Ale co z heroku.

Ja osobiście polecam firebase, jest usługa należąca teraz do googla. Trochę jest to taki uproszczony google cloud. 5gb przestrzeni macie do wykorzystania. Z Punktu widzenia konfiguracji to też google cloud

zajrzyjmy do naszego storage.yml

i dodajmy nowego providera - firebase

firebase:
  service: GCS
  credentials: <%= Rails.root.join("firebase.json") %>
  project: "sampleproject"
  bucket: "sampleproject.appspot.com"

project to nazwa naszego projektu a bucket to project + appspot.com

a plik z credentials za chwilę pokaże wam skąd pobrać

a do gemfila dodajmy

...
gem "google-cloud-storage", "~> 1.11", require: false

teraz potrzebujemy jeszcze projektu na firebase

  • utwórzmy nowy projekt
  • przejdźmy do zakładki storage i dokończmy setup najważniejsze to ustawić gdzie pliki będą trzymane (nie można tego później zmienić)
  • przejdźmy do zakładki settings a następnie service accounts
  • wygenerujmy nowy klucz i umieśćmy zawartośc pliku w naszym repozytorium

pamiętajcie by plik firebase.json dodać do .gitignore w przeciwnym wypadku wasze dane zapiszą się w repozytirum i mogą przypadkowo wyciec. Lepiej tego uniknąć.

w pliku /enviroments/productions.rb dodajmy config.active_storage.service = :firebase by nasza aplikacja na produkcji korzystała z firebasea

jeżeli to wszytsko ma być trzymane na heroku to plik będzie problemem ale możemy lekko zmienić konfig

firebase:
  service: GCS
  credentials:
    type: <%= ENV["gsc_type"] %>
    project_id: <%= ENV["gsc_project_id"] %>
    private_key_id: <%= ENV["private_key_id"] %>
    private_key: <%= ENV["gsc_private_key"] %>
    client_email: <%= ENV["gsc_client_email"] %>
    client_id: <%= ENV["gsc_client_id"] %>
    auth_uri: "https://accounts.google.com/o/oauth2/auth"
    token_uri: "https://accounts.google.com/o/oauth2/token"
    auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs"
    client_x509_cert_url: <%= ENV["gsc_client_x509_cert_url"] %>
  project: <%= ENV["gsc_project"] %>
  bucket: <%= ENV["gsc_bucket"] %>

i każdy klucz dodawać ręcznie

na koniec zostanie nam wrzucenie naszej aplikacji na heroku

i dodanie wszystkich potrzebnych kluczy

na dzisiaj to już wszystko oczywiście active storage to narzędzie wielu możliwości i pewnie w wielu filmach będę do niego wracać

dziękuje za ogładanie

Miłego kodowania!