Skip to content
Lucas Caton

Vídeo: Aprenda Active Storage - parte 2

Aprenda a fazer upload de arquivos para o AWS S3, usar direct upload sem passar pelo seu servidor e também a enviar múltiplos arquivos de uma vez

Lucas Caton

Lucas Caton

@lucascaton
Há 3 dias, publiquei o primeiro vídeo desta série sobre Active Storage, o grande destaque do Rails 5.2; recomendo que você o veja antes de assistir este.
Nesse segundo vídeo, vou mostrar como configurar o Active Storage para:
  • Fazer upload de arquivos para o AWS S3 (serviço de armazenamento de arquivos da Amazon);
  • Usar o direct upload (envio de arquivos do navegador diretamente para o S3, sem passar pelo seu servidor);
  • Fazer upload de vários arquivos de uma só vez.


Arquivos alterados no vídeo:

config/storage.yml

yaml
# ...

amazon:
  service: S3
  access_key_id: xxxxxxxxxxxxxxxxxxxx
  secret_access_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  region: xxxxxxxxxxxxxx
  bucket: xxxxxxx

# ...

config/environments/development.rb

ruby
# ...

config.active_storage.service = :amazon

# ...

app/assets/javascripts/application.js

javascript
// ...

//= require activestorage

// ...

app/models/post.rb

ruby
class Post < ApplicationRecord
  has_many_attached :images
end

app/controllers/posts_controller.rb

ruby
class PostsController < ApplicationController
  # ...

  def post_params
    params.require(:post).permit(:title, :body, images: [])
  end
end

app/views/posts/_form.html.erb

erb
<!-- ... -->

<div class="field">
  <%= form.label :images %>
  <%= form.file_field :images, direct_upload: true, multiple: true %>
</div>

<!-- ... -->

app/views/posts/show.html.erb

erb
<!-- ... -->

<% @post.images.each do |image| %>
  <%= image_tag image, style: 'width: 25%' %>
<% end %>

<!-- ... -->

app/assets/javascripts/direct_uploads.js

javascript
addEventListener("direct-upload:initialize", event => {
  const { target, detail } = event
  const { id, file } = detail
  target.insertAdjacentHTML("beforebegin", `
    <div id="direct-upload-${id}" class="direct-upload direct-upload--pending">
      <div id="direct-upload-progress-${id}" class="direct-upload__progress" style="width: 0%"></div>
      <span class="direct-upload__filename">${file.name}</span>
    </div>
  `)
})

addEventListener("direct-upload:start", event => {
  const { id } = event.detail
  const element = document.getElementById(`direct-upload-${id}`)
  element.classList.remove("direct-upload--pending")
})

addEventListener("direct-upload:progress", event => {
  const { id, progress } = event.detail
  const progressElement = document.getElementById(`direct-upload-progress-${id}`)
  progressElement.style.width = `${progress}%`
})

addEventListener("direct-upload:error", event => {
  event.preventDefault()
  const { id, error } = event.detail
  const element = document.getElementById(`direct-upload-${id}`)
  element.classList.add("direct-upload--error")
  element.setAttribute("title", error)
})

addEventListener("direct-upload:end", event => {
  const { id } = event.detail
  const element = document.getElementById(`direct-upload-${id}`)
  element.classList.add("direct-upload--complete")
})

app/assets/stylesheets/direct_uploads.css

css
.direct-upload {
  display: inline-block;
  position: relative;
  padding: 2px 4px;
  margin: 0 3px 3px 0;
  border: 1px solid rgba(0, 0, 0, 0.3);
  border-radius: 3px;
  font-size: 11px;
  line-height: 13px;
}

.direct-upload--pending {
  opacity: 0.6;
}

.direct-upload__progress {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  opacity: 0.2;
  background: #0076ff;
  transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
  transform: translate3d(0, 0, 0);
}

.direct-upload--complete .direct-upload__progress {
  opacity: 0.4;
}

.direct-upload--error {
  border-color: red;
}

input[type=file][data-direct-upload-url][disabled] {
  display: none;
}
Qualquer dúvida, mande nos comentários!