Witam.
Chciałbym zrobić coś w tym guście:
Ładowanie spakowanego pliku (docelowo katalog ze zdjęciami), automatyczne rozpakowanie i zapisanie poszczególnych elementów.
Czy da się to zrobić? Lub może jest inny prostszy sposób na załadowanie wielu plików (obrazków) przy wykonaniu jednej akcji z poziomu użytkownika?
Mam coś takiego napisane. Do tej aplikacji używałem pluginu file_column, dlatego w pewnym miejscu używam klasy LocalUploadedFile - zachowuje się jak uploadowany plik. Image to model railsowy korzystający z file_column.
Bez żadnych zmian pewnie nie zadziała u Ciebie w aplikacji, ale możesz się na tym wzorować
[code] require ‘zip/zip’
require ‘zip/zipfilesystem’
require ‘tempfile’
require ‘local_uploaded_file’
def add_to_gallery(uploaded_file, gallery)
if uploaded_file.content_type =~ /application/(zip|x-zip-compressed)/
files = []
Zip::ZipInputStream::open(uploaded_file.path) do |zipfile|
while zip_entry = zipfile.get_next_entry
files << zip_entry.to_s unless zip_entry.directory?
end
end
Zip::ZipFile.open(uploaded_file.path) do |zipfile|
files.each do |f|
if zipfile.file.file?(f)
temp = Tempfile.new(File.basename(f))
local_file = LocalUploadedFile.new(temp.path, "image/jpeg")
local_file.write(zipfile.file.read(f))
image = Image.new(:file => local_file)
image.gallery = gallery
image.save
end
end
end
elsif uploaded_file.content_type =~ /image\/jpeg/
temp = Tempfile.new(File.basename(uploaded_file.original_filename))
local_file = LocalUploadedFile.new(temp.path, "image/jpeg")
local_file.write(uploaded_file.read)
image = Image.new(:file => local_file)
image.gallery = gallery
image.save
end
end[/code]
i LocalUploadedFile:
[code] require ‘tempfile’
class LocalUploadedFile
attr_reader :original_filename
attr_reader :content_type
def initialize(path, content_type = 'text/plain')
raise "#{path} file does not exist" unless File.exist?(path)
@content_type = content_type
@original_filename = File.basename(path)
@tempfile = Tempfile.new(@original_filename)
FileUtils.copy_file(path, @tempfile.path)
end
def path #:nodoc:
@tempfile.path
end
alias local_path path
def method_missing(method_name, *args, &block) #:nodoc:
@tempfile.send(method_name, *args, &block)
end
end[/code]
Teraz mam mały problem - obsługa działa ale tylko na kompie, na którym stoi serwer.
Czy problem tkwi w tym że nie korzystam z TempFile?
def upload_dir(file)
require 'zip/zip'
require 'zip/zipfilesystem'
dir_name=file.original_filename.gsub(/.zip/,'')
if file.content_type =~ /application\/(zip|x-zip-compressed)/
Dir.mkdir("public/images/photo/#{dir_name}")
files = []
Zip::ZipInputStream::open(file.path) do |zipfile|
while zip_entry = zipfile.get_next_entry
files << zip_entry.to_s unless zip_entry.directory?
end
end
end
Zip::ZipFile.open(file.path) do |zipfile|
files.each do |f|
if zipfile.file.file?(f)
File.open("public/images/photo/#{dir_name}/#{f}", "wb") do |ff|
ff.write(zipfile.file.read(f))
end
end
end
end
end
Nie mam pojęcia.
Sypnij jakimś komunikatem błędu, opisz co się dzieje, alboco.
Chyba już wiem gdzie jest problem, ale nie rozumiem go ani trochę.
Testowałem na 3 kompach ten sam spakowany plik. W kodzie używam metody .content_type i za każdym razem wynik był inny:
u mnie: application/x-zip-compressed
u kumpla: application/zip
u drugiego kumpla: application/force-download
hmm… w takim wypadku najlepiej próbować obczaić po rozszerzeniu.
Coś takiego zamiast tego ifa sprawdzającego content_type:
if file.original_filename =~ /\.zip$/i
Co do rozpoznawanego content type to mogę od siebie powiedzieć, że miałem coś podobnego jakiś czas temu w aplikacji php. Na dwóch różnych maszynach dostawałem różne wartości dla content-type. Doszedłem do tego, że prawdopodobnie wynika to z różnych plików /etc/mime.types. Prawdopodobnie tutaj jest taka sama sytuacja.
content-type uploadowanego pliku jest ustawiany w zależności od systemu operacyjnego i przeglądarki. Np. IE 6 ustawia image/pjpeg a nie image/jpeg - trzeba na to zwrócić uwagę.