2013-03-10 28 views
8

Próbuję utworzyć proste łącze, które po kliknięciu inicjuje pobieranie dokumentu powiązanego z konkretnym zasobem. Mam model zasobów iw tym modelu jest kolumna o nazwie "dokument". Po kliknięciu linku mogę wyświetlać tekst w wierszu, ale wolałbym go pobrać. Czytałem o typach zawartości i send_file, ale nie udało mi się całkowicie scalić tego, by funkcjonować.Pobieranie pliku z linku załącznika dokumentu Carrierwave

Oto kod, który myślę, że trzeba użyć do linku:
<%= link_to 'Download File', :action => "download_file" %>

ten zgłasza błąd:
ActiveRecord :: RecordNotFound w ResourcesController # show Nie można znaleźć zasobu z id = download_file

Kiedy zmienić odwołują się do tego, że otwiera plik w przeglądarce:
<%= link_to 'Open file', resource.document_url, :target => "_blank" %>

W moim ResourcesController Mam ten sposób zdefiniowane:

def download_file 
    @resource = Resource.find(params[:id]) 
    send_file(@resource.file.path, 
     :filename => @resource.file.name, 
     :type => @resource.file.content_type, 
     :disposition => 'attachment', 
     :url_based_filename => true) 
    end 

Mam trasy ustanowiony w routes.rb tak:

resources :resources do 
    get 'resources', :on => :collection 
    end 

Więc oparciu tego błędu, wydaje się, że moja metoda download_file w module ResourcesController nie można określić identyfikatora rekordu zasobu, z którym dokument jest powiązany.

biegnę: Szyny 3.2.11 Carrierwave 0.8.0 Ruby 1.9.3-p194

chciałbym docenić pewien wgląd w to. Przeszukałem wiele artykułów i nie byłem w stanie znaleźć prostego samouczka. Dzięki.

+0

Dziękuję bardzo. To wszystko działało cuda. Szyny 4 - CarrierWave. –

Odpowiedz

13

Udało mi się to ustalić. Spróbuję wyjaśnić, jak naprawiłem ten problem.

Metoda download_file została poprawnie umieszczona w module ResourcesController, ale nie używałem prawidłowych nazw zmiennych. Oto poprawna definicja metody do moich celów:

def download_file 
    @resource = Resource.find(params[:id]) 
    send_file(@resource.document.path, 
     :type => 'application/pdf', 
     :disposition => 'attachment', 
     :url_based_filename => true) 
    end 

W moim przypadku mam rekord zwrócony w zmiennej @resource który ma dokumentu związanego z nim (znowu używam Carrierwave). Zatem pierwszym argumentem, którego wymaga plik send_file, jest ścieżka (patrz: API for send_file). Ta informacja o ścieżce jest dostarczana przez @ resource.document.path.

send_file przyjmuje kilka innych argumentów, które wydają się opcjonalne, ponieważ potrzebowałem tylko trzech z nich. Zobacz dokumentację API dla innych argumentów.

Jedną z tych, które rzuciły mi błąd, był typ :. Podałem mu zmienną "@ resource.file.content_type", ale najwyraźniej szukałem literału. Kiedy zdałem aplikację/pdf, zadziałało. Bez wyraźnego ustawienia tego pliku pobierany plik nie ma dodanego rozszerzenia pliku. W każdym razie dla mojej aplikacji ten dokument może być różny od różnych typów mime od pdf do word do mp4. Więc nie jestem pewien, jak określić wiele.

Naprawdę ważnym argumentem dla moich celów (pobieranie zamiast wyświetlania w przeglądarce) jest: dyspozycja, która musi być ustawiona na "załącznik", a nie "inline".

Drugi argument: url_based_filename jest najwyraźniej używany do określenia nazwy pliku z adresu URL. Ponieważ nie dostarczam nazwy pliku, być może jest to jedyny sposób, aby przekazać to do pobieranego pliku, ale nie jestem tego pewien.

Musiałem także zmienić tag link_to do tego:
<%= link_to 'Download File', :action => 'download_file', :id => resource.id %>

Zauważ, że dostarczanie: id symbol z ID bieżącego zasobu dostarczyły szczegółowych informacji potrzebnych do identyfikacji zasobu w pytaniu.

Mam nadzieję, że pomoże to komuś innemu. To musi być bardzo oczywiste dla wszystkich innych, ponieważ nie znalazłem żadnych podstawowych samouczków dotyczących pobierania plików. Wciąż się dużo uczę.

AKTUALIZACJA: Musiałem się z tym bawić, aby uzyskać pożądane zachowanie. Oto nowa metoda, która działa:

 def download_file 
     @resource = Resource.find(params[:id]) 
     send_file(@resource.document.path, 
       :disposition => 'attachment', 
       :url_based_filename => false) 
     end 

Dzięki tym zmianom nie muszę już ustawiać: type. Ustawienie ": url_based_filename => true" utrzymywało nazwę pliku po identyfikatorze rekordu w adresie URL. Ustawienie tego na false wydaje się sprzeczne z intuicją w oparciu o moje odczytanie funkcji tego argumentu, jednak czyniąc to przyniosło pożądane rezultaty nazwania pliku po rzeczywistej nazwie pliku.

użyłem również mime-types gem i dodać następujące do mojego pliku video_uploader.rb:

require 'carrierwave/processing/mime_types' 

class VideoUploader < CarrierWave::Uploader::Base 
include CarrierWave::MimeTypes 
process :set_content_type 

Ten gem najwyraźniej ustawia mime-type odgadnąć z rozszerzenia pliku w pliku. Wykonanie tej czynności sprawiło, że nie muszę ustawiać: wpisz jawnie w argumentach send_file w mojej metodzie download_file.

+0

Dzięki za te informacje! – tkrajcar

+0

Używam klejnotu Carrierwave, a po pobraniu pliku, jeśli nazwa tego pliku zawiera spację, jest konwertowana na podkreślenia. Jak usunąć podkreślenie z nazwy pliku podczas pobierania? –

Powiązane problemy