Upload e Validação de Imagens e Arquivos com a gem Paperclip e Rails
Fala pessoal, beleza?
Hoje estou aqui para mostrar como fazer upload e validação de imagens e arquivos no Ruby on Rails (versão 3.2.8) com a gem Paperclip.
Irei utilizar o projeto que criei no tutorial onde ensino como iniciar com Rails, ele só tem uma conexão com o banco de dados MySQL e a rota raiz definida.
Índice
- Gerando CRUD
- Instalando e configurando a gem Paperclip
- Usando a gem Paperclip
- Personalizando caminho de upload
- Adicionando validações
Escopo
Vamos supor que temos um cadastro de carros para fazer que deve conter os seguintes campos:
- nome: string
- descrição: text
- imagem: string
Gerando um CRUD de registros
Para começar vamos gerar as páginas responsáveis por fazer cadastro, edição, exclusão e exibição de nossos registros. Para isso, abra o terminal na pasta do projeto e digite o comando rails g scaffold Car name:string description:text image:string
para gerar os arquivos e depois rake db:migrate
para criar a tabela de carros:

Se iniciarmos o servidor (rails s
) e acessarmos o projeto na url http://0.0.0.0:3000/cars
teremos a tela onde podemos manipular nossos registros.

Instalando e configurando a gem Paperclip
Agora que temos nosso CRUD funcionando vamos implantar o upload da imagem dos carros.
Vamos dizer ao Rails para usar a gem Paperclip, abra o arquivo Gemfile
na pasta do projeto e adicione gem "paperclip", "~> 3.0"
. Feito isso, rode o comando bundle install
no terminal para obtermos a gem e suas dependências.
O Paperclip usa a biblioteca ImageMagick
para manipular imagens, devemos garantir que ela esteja instalada e com acesso, para isso rode which convert
no terminal, copie o resultado (você obterá algo como /usr/bin/convert
, desconsidere a parte do convert
) e adicione a seguinte linha no arquivo de configuração de ambiente:
Paperclip.options[:command_path] = "/usr/bin/"
No caso do ambiente de desenvolvimento, adicionamos ela no arquivo config/environments/development.rb
.
Usando a gem Paperclip
Já temos a gem instalada, agora vamos abrir o model de carros (app/models/car.rb
) e dizer que iremos fazer upload de arquivos no campo image
através da linha abaixo:
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "120x90#" }
Observer a chave styles
, ela serve para definir os tamanhos de miniaturas que desejamos criar, nesse caso estou criando duas, uma com tamanho de 300x300 (medium) e outra com tamanho de 120x90 (thumb). O #
na frente diz para cortar a imagem centralizada, mantendo assim a dimensão solicitada e >
diz que a imagem só deve ser redimensionada se ela for maior do que a medida. Veja mais aqui.
Precisamos alterar o campo de imagem no formulário que está como input text para input file, abra o partial do formulário (app/views/cars/_form.html.erb
) e deixe como abaixo.
<div class="field">
<%= f.label :image %><br />
<%= f.file_field :image %>
</div>
Não podemos esquecer de ativar o multipart/form-data
no formulário, para isso adicione :html => { :multipart => true }
na tag de criação do form, veja:
<%= form_for(@car, :html => { :multipart => true }) do |f| %>
Também temos que alterar o nome do campo no banco de dados de image
para image_file_name
pois esse é o padrão do Paperclip para armazenar o nome/caminho da imagem.
Faça um teste e veja que o upload já está funcionando..

Só que algo está errado ai, não queremos exibir o caminho da imagem, e sim ela, para isso abra o arquivo de listagem de carros (app/views/cars/index.html.erb
) e substitua a linha:
<td><%= car.image %></td>
por
<td><%= image_tag(car.image.url(:thumb)) %></td>
Agora estamos chamando o helper image_tag
passando como parâmetro a url da imagem pequena (thumb
).
:medium
ou :original
para exibir a imagem no tamanho original.
Personalizando caminho de upload
Se você quer escolher onde as imagens serão salvas é possível através das chaves path
e url
, veja:
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "120x90#" },
:path => ':rails_root/public/images/cars/:id-:basename-:style.:extension',
:url => '/images/cars/:id-:basename-:style.:extension'
Aqui digo para salvar as imagens de carros na pasta public/images/cars
e defino a url para o mesmo caminho.
Adicionando validações
Com certeza não podemos deixar de fora as validações, vamos ver algumas..
Presença obrigatória
Adicione a chamada para o método validates_attachment
passando o campo a ser validado e definindo a presença obrigatória.
validates_attachment :image,
:presence => true
Tipo de arquivo (content type)
Usando um array de content type:
validates_attachment :image,
:content_type => { :content_type => ['image/jpg', 'image/png'] }
Ou por expressão regular, permitindo qualquer tipo de imagem:
validates_attachment :image,
:presence => true,
:content_type => { :content_type => /image/ }
Para fazer essa validação precisamos adicionar attr_accessor :image_content_type
em nosso model para que o atributo consiga ser lido e escrito (get e set).
Tamanho de arquivo (file size)
validates_attachment :image,
:presence => true,
:size => { :in => 0..10.kilobytes }
ou
validates_attachment :image,
:presence => true,
:size => { :in => 0..3.megabytes }
Assim como o de cima, precisamos adicionar attr_accessor :image_file_size
em nosso model.
Dimensões de imagens
Uma validação que sem dúvida é muito importante também é a de dimensões de imagem, com ela podemos definir um tamanho mínimo da figura a ser feito upload.
validate :file_dimensions, :unless => 'errors.any?'
def file_dimensions
if image.size
dimensions = Paperclip::Geometry.from_file(image.queued_for_write[:original].path)
if dimensions.width < 120 || dimensions.height < 90
errors.add(:image,'deve ter no minimo 120px de largura por 90px de altura')
end
end
end
Bem simples né, criamos um método que verifica se tem imagem pra subir, pega as dimensões da imagem original e faz a verificação. Substitua 120
e 90
pela largura e altura mínima que você deseja respectivamente.
Por hoje é só pessoal, o que vocês acharam?
Abraços.