Atualmente estou trabalhando em uma aplicação Rails que faz inúmeros acessos à imagens guardadas em um banco de dados. Acontece que as imagens são ENORMES! E na maioria das vezes (pra não dizer todas) não há a necessidade de apresentar para o usuário a imagem em alta resolução.
Então pensei em thumbnails. Aquelas imagens pequenininha, que abrem rapidamente, e que geralmente quando clicamos sobre elas, abrimos a imagem original em alta resolução.
Bom, mas como fazer isso em Rails?
Recorri ao bom e velho Google e encontrei algumas soluções.
Ruby possui algums gems que auxiliam na manipulação de imagens utilizando ImageMagick, dentre eles o rmagick, image_science e o minimagick. Durante a pesquisa, descobri também alguns plugins para rails que facilitam o upload de arquivos binários, file_column, acts_as_attachment e atachment_fu.
Depois de ler algo sobre todos eles, resolvi usar, minimagick + atachment_fu. Como esperado, a junção dos dois mostrou-se extremamente eficiente, tornando meu trabalho mais simples e menos demorado.
Então, agora, nesse artigo, mostrarei como utiliza-los para fazer upload de imagens e guarda-las no banco de dados em versão thumbnails e original.
Obs: Todos os passos seguidos nesse tutorial foram realizados usando Rails 2.0.2 em um Ubuntu 7.10
Primeiramente, precisamos instalar o ImageMagick, que é o responsável por transformar usas imagens em thumbnails.
No caso do ubuntu é bem fácil!
sudo apt-get install imagemagick
Agora se você usa outra distribuição linux, windows ou mac, é só entrar no site oficial do ImageMagick e fazer o download da versão apropriada.
Depois temos que instalar o gem minimagick.
sudo gem install mini_magick
e criar nossa aplicação rails
rails thumbnails
Como utilizaremos o plugin atachment_fu, precisamos baixá-lo e adicioná-lo ao projeto.
ruby script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/
Não se esqueça de configurar seu banco de dados (config/database.yml).
Pronto! Agora efetivamente podemos começar.
Como usaremos o attachment_fu, devemos criar 2 modelos, um (db_file) que será o responsável por armazenar no banco de dados as imagens (sejam elas em tamanho original ou thumbnails) e outro (image) para descrevê-las.
Par isso, vamos executar os seguintes comando
ruby script/generate model db_file
ruby script/generate scaffold image name:string description:text db_file_id:integer filename:string content_type:string size:integer width:integer height:integer parent_id:integer thumbnail:string created_at:datetime
O comando scaffold é usado para facilitar nosso trabalho, pois ele criará praticamente toda a estrutura da nossa aplicação.
Agora vamos editar os seguintes arquivos
Arquivo da migração da tabela db_files (001_create_db_files.rb)
class CreateDbFiles < ActiveRecord::Migration
def self.up
create_table :db_files do |t|
t.column :data, :longblob
end
enddef self.down
drop_table :db_files
end
end
Note que essa tabela tem um campo longblob onde serão armazenados os arquivos, e que seu nome (db_files) é padrão do plugin attachment_fu.
Arquivo da migração da tabela images (002_create_images.rb)
class CreateImages < ActiveRecord::Migration
def self.up
create_table :images do |t|
t.string :name
t.text :description
t.integer :db_file_id
t.string :filename
t.string :content_type
t.integer :size
t.integer :width
t.integer :height
t.integer :parent_id
t.string :thumbnail
t.datetime :created_att.timestamps
end
enddef self.down
drop_table :images
end
end
Esse arquivo foi totalmente gerado pelo scaffold e está pronto para ser usado. Note que exceto os campo name e description, todos os outros são de uso do plugin attachment_fu.
Obs: Adicionei os campos name e description somente para ilustrar que podemos adicionar outros campos, e não somentes os de uso do plugin.
Modelo Image (image.rb)
class Image < ActiveRecord::Base
has_attachment :storage => :db_file,
:max_size => 5.megabytes,
:thumbnails => { :thumb => ‘80×80>’},
:processor => :MiniMagickvalidates_as_attachment
end
Aqui descrevemos que o modelo terá um anexo, e que geraremos um thumbnail chamado thumb de no máximo 80×80 utilizando o processor MiniMagick. Definimos também que o tamanho máximo do arquivo será de 5MB e que ele será armazenado na tabela db_file.
Obs: :storage => :db_file não é necessário, pois é padrão do attachment_fu
View index do controlador Images (index.html.erb)
<h1>Listing images</h1>
<table>
<tr>
<th>Image</th>
</tr><% for image in @images %>
<tr>
<td><%= image_tag h url_for(:action => “showImage”, :id =>image)%></td>
<td><%= link_to ‘Show’, image.parent %></td>
<td><%= link_to ‘Destroy’, image, :confirm => ‘Are you sure?’, :method => :delete %></td>
</tr>
<% end %>
</table><br />
<%= link_to ‘New image’, new_image_path %>
Retiramos todos os campos que não são interessantes, e deixamos somente as ações de mostrar e de destruir uma imagem armazenada.
Note:
- que a imagem será formada na action showImage do controlador Images (veremos isso mais para frente);
- e que a action show tem id=>image.parent (isso ocorre porque apresentaremos aqui somente os thumbnails, e quando o usuário clicar em show, a imagem original, ou seja, a parent, deverá ser mostrada)
View new do controlador Images (new.html.erb)
<h1>New image</h1>
<%= error_messages_for :image %>
<% form_for(@image, :url => {:action=>”create”}, :html => { :multipart => true }) do |f| %>
<p>
<b>Name</b><br />
<%= f.text_field :name %>
</p><p>
<b>Description</b><br />
<%= f.text_area :description %>
</p><p>
<b><label for=”uploaded_data”>Image:</label></b><br />
<%= f.file_field :uploaded_data %>
</p><p>
<%= f.submit “Create” %>
</p>
<% end %><%= link_to ‘Back’, images_path %>
Retire todos os campos, exceto o name e o description, e adicione o campo file_field para que seja possível fazer upload de arquivos. Todos os outros campos serão preenchidos pelo plugin attachment_fu automaticamente. Note que o form deve permitir :multipart => true.
View show do controlador Images (show.html.erb)
<p>
<b>Name:</b>
<%=h @image.name %>
</p><p>
<b>Description:</b>
<%=h @image.description %>
</p><p>
<%= image_tag h url_for(:action => “showImage”, :id =>params[:id])%>
</p><p>
<b>Created at:</b>
<%=h @image.created_at %>
</p>|
<%= link_to ‘Back’, images_path %>
Novamente retiramos os campos que não interessam.
Controlador Images (images_controller.rb)
class ImagesController < ApplicationController
def index
@images = Image.find(:all,:conditions=>”thumbnail=’thumb’”)respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @images }
end
end
def show
@image = Image.find(params[:id])respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @image }
end
end
def new
@image = Image.newrespond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @image }
end
enddef create
@image = Image.new(params[:image])respond_to do |format|
if @image.save
flash[:notice] = ‘Image was successfully created.’
format.html { redirect_to(@image) }
format.xml { render :xml => @image, :status => :created, :location => @image }
else
format.html { render :action => “new” }
format.xml { render :xml => @image.errors, :status => :unprocessable_entity }
end
end
enddef destroy
@image = Image.find(params[:id])
@thumb = Image.find(@image.parent)
@image.destroy
@thumb.destroyrespond_to do |format|
format.html { redirect_to(images_url) }
format.xml { head :ok }
end
enddef showImage
image = Image.find(params[:id])
send_data(image.db_file.data,:type=>image.content_type,:disposition=>”inline”)
end
end
As observações mais importantes que devem ser feitas nesse controlador são:
- na action index temos @images = Image.find(:all,:conditions=>”thumbnail=’thumb’”), ou seja, estamos selecionando somente as imagens thumb (que definimos como no máximo 80×80)
- na action destroy, destruímos 2 imagens: a original e a thumbnail
Agora execute
rake db:migrate
ruby script/server
e teste sua aplicação
http://localhost:3000/images/
Se você quiser fazer download dos arquivos desse tutorial, clique aqui.
May 19th, 2008 at 2:21 am
Olá estou seguindo o que você sugeriu neste artigo para trabalhar com upload de imagens e estou tendo o seguinte erro:
ImageMagick command (mogrify -strip -resize “80×80>” “C:/DOCUME~1/Angel/CONFIG~1/Temp/minimagick1932-1.JPG”) failed: Error Given 256
O que você sugere que seja este erro? Ocorre quando tento adicionar uma nova imagem.
Antes da versão Rails 2.0 eu utilizava o file_column, mas ficou depreciado e estou tentando aprender a utilizar o arrachment_fu + minimagick para efetuar upload de imagens.
May 19th, 2008 at 7:51 pm
Olá Angelina
Quando você utilizava file_column, o upload de imagens usando minimagick para gerar thumbnails funcionava? Porque, me parece que o erro está no minimagick.
Pelo que vejo você está usando Windows… e nesse tutorial utilizei um Ubuntu 7.10, e não tenho experiência em desenvolvimento rails com minimagick no windows. Já vi algumas pessoas reclamando na internet que o minimagick não funciona muito bem nesse sistema operacional…
Tentarei encontrar alguma solução, e qualquer coisa posto aqui no blog.
(ah, e se você solucionar o problema ficarei muito contente em saber como)
June 15th, 2008 at 6:44 pm
Quando tento submeter, obtenho o seguinte erro: “Size is not included in the list” e a nova imagem não é salva. Podem me ajudar? Obrigado.
June 30th, 2008 at 10:35 am
Olá Igor,
Você acha que consigo usar o attachment_fu para adioncar mais de uma imagem no mesmo registro no banco de dados. Estou desenvolvendo um site que preciso colocar quatro imagens no mesmo registro. Desde já agradeço. Vou acompanhar seu blog a partir de agora e colaborar no que puder.
July 2nd, 2008 at 7:13 am
Olá Luiz, então, o padrão do attatchment_fu é criar 2 tabelas, uma contendo os arquivos binarios (blob) e outra contendo informações sobre esses arquivos binários (nome, descrição, tamanho, etc).
Então para cada arquivo que você adicionar irá gerar 2 entradas no banco de dados: uma na tabela de arquivos binários e outra na que descreve esse arquivo. Acho até essa estrutura bem organizada.
Mas se você tem q adicionar 4 imagens em uma única tabela porque é uma restrição da sua aplicação… acredito q a solução é utilizar o upload comum, sem plugins.
Espero ter ajudado.
Abraço
December 11th, 2008 at 2:46 pm
Seguinte o Ígor disse que já viu algumas pessoas reclamando na internet que o minimagick não funciona muito bem no Windows, alguem já utilizou rmagick ou image_scienc ou alguma outra gem que execute a mesma função do minimagick nesse SO e que funcionou bem