Se você quer que sua aplicação Rails seja capaz de lidar arquivos, como imagens, videos, pdfs, etc. Você está no lugar certo.
Hoje, nós vamos aprender sobre Active Storage.
O que é Active Storage
Active Storage é uma ferramenta que facilita o upload de arquivos para serviço de armazenamento em nuvem como Amazon S3, Google Cloud Storage ou Microsoft Azure e anexa esses arquivos a objetos Active Record. Ele também vem com um serviço baseado em disco local para desenvolvimento e teste e suporta espelhamento de arquivos para serviços subordinados para backups e migrações.
Observação: Eu não vou mostrar como que integrar o Active Storage com o serviço de armazenamento em nuvem. Eu só vou focar em ambiente de desenvolvimento.
Mas, antes de instalar Active Storage na sua aplicação, é necessário alguns software de terceiro para ter suporte em analise e processamento de arquivos.
Eu vou deixar uma lista de software.
- libvips v8.6+ ou ImageMagick para analise e transformação de imagem.
- ffmpeg v3.4+ para pré-visualizações de vídeo e ffprobe para analise de video/audio
- poppler ou muPDF para pré-visualizações de PDF
E também é necessário colocar uma gem image_processing
, se sua aplicação vai usar arquivo do tipo imagem.
Antes de instalar e usar software de terceiros, certifique-se de compreender as implicações de licenciamento de fazê-lo. O MuPDF, em particular, é licenciado sob AGPL e requer uma licença comercial para alguns usos.
Eu vou ensinar a instalar o Active Storage criando uma aplicação, porque eu acho muito mais melhor você ver a construção da aplicativo.
Então vamos criar aplicação
Criando uma aplicação
A aplicação que eu vou criar vai ser um simples armazenamento de arquivos, em que vai ter dois models e controllers, Usuario
e Arquivo
.
rails new armazenamento
cd armazenamento
Vamos colocar uma gem no Gemfile
para que possa ter suporte de imagem.
echo "gem 'image_processing'" >> Gemfile
bundle install
Com gem instalado, vamos instalar o Active Storage.
rails active_storage:install
Esse comando cria uma migração, em que tem três tabelas active_storage_blobs
, active_storage_attachments
e active_storage_variant_records
.
Eu não vou explicar cada um dele, mas saiba que são essas tabelas que vai armazenar os arquivos.
Como ele gerou uma migração, vamos migrar ele.
rails db:migrate
Agora, vamos criar os models e os controllers.
Antes de criar um model, tenho que falar que existe duas maneiras de anexar o arquivo no model, uma é usando o generator e outro é colocando o código na mão, o que não é complicado de fazer.
Primeiro, vamos usar o generator no model Usuario
.
rails g model Usuario email senha avatar:attachment
Como você pode ver o tipo attachment
, ele indica que esse model vai ter um anexo, ou seja, vai ter somente um arquivo, se você quer que seja vários arquivos, basta usar o tipo attachments
.
Beleza, vamos ver o que ele gerou para nós, vá para o arquivo app/models/usuario.rb
.
# app/models/usuario.rb
class Usuario < ApplicationRecord
has_one_attached :avatar
end
O has_one_attached
é uma macro que configura uma relação um para um entre o registro e o arquivo, ou seja, cada registro só pode ter um arquivo.
Isso é perfeito para gente, pois nós queremos que seja uma imagem do usuário.
E o que generator gerou foi isso, ou seja, se eu não quiser usar o generator, basta colocar esse código no model e pronto.
Então, vamos criar um model sem usar o tipo attachment
ou attachments
e colocar o código na mão.
rails g model Arquivo
Agora abra no arquivo app/models/arquivo.rb
para colocar o código.
# app/models/arquivo.rb
class Arquivo < ApplicationRecord
has_many_attached :arquivos
end
Você pode ter percebido que eu escrevi diferente do código de cima.
O has_many_attached
é uma macro que configura uma relação de um para muitos entre o registro e os arquivos, ou seja, cada registro pode ter mais de um arquivo.
Viu, é simples implementar sem o generator.
Agora que criamos os models, vamos migrar eles.
rails db:migrate
Com models criado e migrado, vamos criar os controllers.
rails g controller Usuarios index show new edit
rails g controller Arquivos index show new edit
Agora vamos editar esses controllers. vamos primeiro para app/cotrollers/usuarios_controller.rb
.
# app/cotrollers/usuarios_controller.rb
class UsuariosController < ApplicationController
before_action :define_usuario, except: [:index, :new, :create]
def index
@usuarios = Usuario.all
end
def show
end
def new
@usuario = Usuario.new
end
def create
@usuario = Usuario.new(usuario_params)
if @usuario.save
redirect_to usuario_path(@usuario)
else
render :new
end
end
def edit
end
def update
if @usuario.update(arquivo_params)
redirect_to usuario_path(@usuario)
else
render :edit
end
end
def destroy
if @usuario.destroy
redirect_to usuarios_path
end
end
private
def usuario_params
params.require(:usuario).permit(:email, :senha, :avatar)
end
def define_usuario
begin
@usuario = Usuario.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to usuarios_path, status: :not_found
end
end
end
Como você viu o código que eu escrevi, não tem nada demais, ou seja, a imagem vai ser salva, se o usuário colocar uma imagem no form.
Só que a história muda um pouquinho, quando nós estamos lidando em que aceita vários arquivos.
Então abra o arquivo app/controllers/arquivos_controller.rb
e coloque o código abaixo.
# app/controllers/arquivos_controller.rb
class ArquivosController < ApplicationController
before_action :define_arquivo, except: [:index, :new, :create]
def index
@arquivos = Arquivo.all
end
def show
end
def new
@arquivo = Arquivo.new
end
def create
@arquivo = Arquivo.new(arquivo_params)
if @arquivo.save
redirect_to arquivo_path(@arquivo)
else
render :new
end
end
def edit
end
def update
if @arquivo.update(arquivo_params)
redirect_to arquivo_path(@arquivo)
else
render :edit
end
end
def destroy
if @arquivo.destroy
redirect_to arquivos_path
end
end
private
def arquivo_params
params.require(:arquivo).permit(arquivos: [])
end
def define_arquivo
@arquivo = Arquivo.where(id: params[:id]).includes(arquivos_attachments: :blob)
@arquivo = @arquivo[0]
redirect_to arquivos_path, status: :not_found if @arquivo.nil?
end
end
Se você observar o código, talvez você vai ver algo que nunca tenha visto antes, percebeu?
Se não percebeu, observe no método arquivo_params
e me diz o que tem diferente do controller Usuario
e Arquivo
?
No controller usuario, o avatar está igual aos outros atributos, enquanto no controller arquivo, ele está com um array.
Então, lembre-se de que se você estiver lidando com muitos arquivos, coloque o array, se não, use um symbol
.
E também outra diferença, no método define_arquivo
, eu utilizei o where
e o includes
. O motivo de fazer isso foi para evitar o problema de n+1, se não sabe sobre esse problema, eu recomendo que pesquise sobre isso.
Agora, com controllers criado, vamos editar as rotas, abra o arquivo config/routes.rb
.
# config/routes.rb
Rails.application.routes.draw do
resources :arquivos
resources :usuarios
end
Com models, controllers e rotas editado, agora faltam os views.
Primeiro, vamos editar views de usuarios.
<!-- app/views/usuarios/index.html.erb -->
<% @usuarios.each do |usuario| %>
<%= link_to usuario.email, usuarios_path(usuario)%>
<% end %>
<%= link_to "new", new_usuario_path %>
<!-- app/views/usuarios/new.html.erb -->
<%= form_with model: @usuario, url: usuarios_path do |form| %>
<%= form.label :email %>
<%= form.text_field :email %>
<%= form.label :senha %>
<%= form.password_field :senha %>
<%= form.label :avatar %>
<%= form.file_field :avatar %>
<%= form.submit %>
<% end %>
Para que possa enviar um arquivo a partir de um form
, você pode usar o file_field
.
<!-- app/views/usuarios/show.html.erb -->
avatar: <%= image_tag(@usuario.avatar) %> <br>
email: <%= @usuario.email %>
Para poder exibir uma imagem, você pode usar o image_tag
.
Agora rode o servidor e vai para url localhost:3000/usuarios
e crie um usuario com imagem e veja a coisa funciona.
Agora, vamos editar os views de arquivos.
<!-- app/views/arquivos/index.html.erb -->
<% @arquivos.each do |arquivo| %>
<%= link_to arquivo.id, arquivo_path(arquivo)%>
<% end %>
<%= link_to "new", new_arquivo_path %>
<!-- app/views/arquivos/new.html.erb -->
<%= form_with model: @arquivo, url: arquivos_path do |form| %>
<%= form.label :arquivos %>
<%= form.file_field :arquivos, multiple: true %>
<%= form.submit %>
<% end %>
Pode perceber que file_field
é diferente do usuario, o multiple: true
indica que esse campo aceita vários arquivos.
<!-- app/views/arquivos/show.html.erb -->
<% @arquivo.arquivos.each do |arquivo| %>
<% if arquivo.content_type.start_with? "image" %>
<%= image_tag arquivo %>
<% elsif arquivo.content_type.start_with? "video" %>
<%= video_tag( url_for(arquivo), controls: true ) %>
<!-- o video_tag recebe o primeiro argumento uma url do arquivo e esse controls é para ativar o controle do video -->
<% else %>
<!-- Se não for uma imagem e nem video, baixe ele -->
<%= link_to(arquivo.filename, rails_blob_path(arquivo, disposition: "attachment")) %>
<!-- o arquivo.filename mostra o nome do arquivo -->
<!-- o rails_blob_path cria um link de download -->
<% end %>
<br>
<% end %>
Agora vá para url localhost:3000/arquivos
e adicione vários arquivos de tipo diferente.
Você pode notar, se você colocou um arquivo que não seja imagem e video, ao clicar no arquivo, ele vai fazer download.
E nós acabamos por aqui.
Então, espero que tenha ajudado e tchau!
Top comments (0)