Page 155 of 173

Rails + przechowywanie wielu obrazów (miniaturek, avatarów, zdjęć) w systemie

Przeglądając devpytania natknąłem się na pytanie dotyczące przechowywania zdjęć użytkowników w serwisie - biorąc pod uwagę ilości "hurtowe" (link).

Nie miałem potrzeby aby wdrażać takie rozwiązanie, ponieważ nie pisałem nigdy części systemu, która miałaby przechowywać ponad 32k plików (chociaż ostatnio się to zmieniło ;) ). Wychodząc naprzeciw wyzwaniu, postanowiłem dodać taką opcję i jak to bywa w wypadku Railsów - nie zajęło mi to zbyt wiele czasu.

Rozwiązanie znalazłem tutaj. Jest ono proste jak konstrukcja cepa a jego wdrożenie nie zajmuje zbyt wiele czasu.

W katalogu config/initializers tworzymy sobie plik, np o nazwie: paperclip_extensions.rb czy tam czymś podobnym, po czym wstawiamy do tego pliku taki oto kod:

Paperclip.interpolates :hashed_path do |attachment, style|
  hash = Digest::MD5.hexdigest(attachment.instance.id.to_s + 'cos_tam_tajnego')
  hash_path = ''
  3.times { hash_path += '/' + hash.slice!(0..2) }
  hash_path[1..12]
end

Mimo że pierwotny autor na blogu uważa że cos_tam_tajnego nie jest istotne, ja pozwolę się z nim nie zgodzić ;)

Dodanie soli do tego hasha, sprawia że ktoś kto chciałby "zassać" nasze zdjęcia, przy pomocy jakiegoś kodu automatycznego, będzie miał utrudnione zadanie.

Nie dając soli, potencjalny "złodziej" bardzo szybko zauważy prawidłowość pt: MD5(id) i podział na 3 części. Stosując tutaj sól oraz moje rozwiązanie z tego wątku - zabezpieczamy się w dużym stopniu przed tego typu zagrywkami.

Po dodaniu tego rozszerzenia do Paperclipa, otrzymujemy nowe słowo "klucz" do wykorzystania z tym pluginem. Jest to :hashed_path który możemy wykorzystać tak samo jak np: :id_:style.:extension, tworząc przykładowo taką oto ścieżkę:

:url => "/pictures/:hashed_path/:id/:id_:style.:extension"

:hashed_path zostanie zamieniony na strukturę katalogów w stylu /ghw/jre/fhw. Dzięki temu w jednym katalogu nie będzie przechowywana zbyt duża liczba plików co mogłoby się skończyć problemami z systemem plików.

Według mnie implementacja tego kodu jest na tyle prosta i szybka, że warto ją włączać nawet w projekty które nie mają w założeniach być "super obciążone", ponieważ jak to w internecie bywa - wszyscy wiemy ;)

Ruby on Rails, reset_session i utrata zawartości sesji

Logując użytkownika (czy też innego aktora) w systemie, powinniśmy wykonywać reset sesji. Jest to jedno z podstawowych zabezpieczeń przed atakami typu session fixation. Odbywa się to przez wywołanie metody reset_session.

Ma to jednak swoje minusy. Wszystko co mieliśmy w sesji zostanie utracone.

Jest na to jednak bardzo proste rozwiązanie, wystarczy zapamiętać "na chwilę" wartości które mieliśmy w sesji, a następnie je przywrócić. Najprościej będzie to zrobić, nadpisując w naszym kontrolerze (lub kontrolerze po którym dziedziczymy - według potrzeb) metodę reset_session, w taki oto sposób:

  # Resetuje sesję ale zostawiając język i przekierowanie
  def reset_session
    lang = session[:locale]
    url = session[:request_uri]
    super
    session[:request_uri] = url
    session[:locale] = lang
  end

Warto też pamiętać że po wykonaniu resetu, poprzednie ID sesji jest utracone, a wywołanie po resecie metody:

request.session_options[:id]

zakończy się zwróceniem nila.

Z tego powodu lepiej nie bazować na ID sesji, jako kluczu obcym. O wiele lepiej przetrzymywać takie klucze bezpośrednio w sesji (kluczem może być generowany np. na podstawie id sesji + soli, hash) a kiedy trzeba "kopiować" za pomocą sposobu pokazanego powyżej.

Poleganie na ID sesji może skończyć się naprawdę źle ;)

Copyright © 2025 Closer to Code

Theme by Anders NorenUp ↑