Skip to content

kandebonfim/ruby-dev-test-1

 
 

Repository files navigation

O Desafio

Desenvolver a camada de modelos de um sistema de arquivos persistido em um banco de dados SQL onde seja possível criar diretórios e arquivos. Os diretórios poderão conter sub-diretórios e arquivos. O conteúdo dos arquivos podem estar ser persistidos como blob, S3 ou mesmo em disco.

A soluçãos deverá ser escrita majoritariamente em Ruby com framework Ruby on Rails.

Realizar um fork deste repositório.

Minha resolução

Screen Shot 2021-11-08 at 17 24 04

Instruções

$ git clone git@github.com:kandebonfim/ruby-dev-test-1.git
$ cd ruby-dev-test-1/
$ bundler
  ↳ Caso o comando não esteja disponível: gem install bundler
$ yarn --check-files
  ↳ Caso o comando não esteja disponível: npm install -g yarn
$ rails db:setup
  ↳ alias de rails db:drop db:create db:migrate db:seed
$ rails s

A aplicação estará rodando em http://localhost:3000/

Para repopular o banco com novas pastas e arquivos, basta rodar:

$ rails db:drop db:setup

Modelo de dados

Criei uma app Rails (6.0.3) na raiz do projeto e optei por mudar o adapter da database de sqlite3 para pg. Depois de pensar um pouco no modelo de dados resolvi trabalhar com 2 models: Folder e Item.

models/folder.rb

class Folder < ApplicationRecord
  # Relacionamento recursivo entre pastas
  belongs_to :folder, optional: true
  has_many :subfolders, class_name: "Folder", foreign_key: "root_id"
  
  # Arquivos pertencentes a pasta
  has_many :items, dependent: :destroy
end

models/item.rb

class Item < ApplicationRecord
  belongs_to :folder
  
  # Active Storage
  has_one_attached :file
end

Como File é uma classe já definida no ruby, criar uma classe homônima dentro do rails iria requerer várias adaptações para evitar conflitos. Optei então por Item.

Uma abordagem descartada

Depois de rodar rails active_storage:install e migrar o banco novamente, percebi que também poderia trabalhar apenas com a model Folder e utilizar has_many_attached :file para permitir múltiplos arquivos em uma pasta. Porém, decidi seguir com a abordagem original por conseguir armazenar outros campos no modelo Item sem impedir que outros novos modelos utilizem o active storage de maneira limpa futuramente.

Populando o banco

Resolvi escrever um seeds.rb pra popular o banco com pastas e arquivos de maneira programática usando o picsum.photos que fornece imagens de placeholder com as dimensões informadas na própria url de requisição.

# Criando uma pasta raiz
root = Folder.create(title: 'Pasta Raiz')

# Número de pastas e imagens por pasta
n_folders = 7
n_items = 4

# Parametros de scrapping das imagens
thumb_width = 400
thumb_ratio = 9 / 16.to_f # Imagens sempre em proporção de 16/9
thumb_height = (thumb_width * thumb_ratio).to_i

# Iniciando a barra de progresso
progressbar = ProgressBar.create(total: n_folders * n_items, format: '%t: |%B| %a %e')

# Criando as demais pastas e arquivos
(1..n_folders).each do |s|
  subfolder = root.subfolders.create(title: "Pasta #{s}")
  progressbar.log "→ Pasta #{s}"

  (1..n_items).each do |i|
    url = URI.parse("https://picsum.photos/#{thumb_width}/#{thumb_height}") # Trazendo imagens do picsum.photos
    filename = i
    item = subfolder.items.create(name: filename)
    item.file.attach(io: URI.open(url), filename: filename)
    progressbar.log "  ↳ Arquivo #{i}"
    progressbar.increment
  end
end

# Colocando a última pasta dentro da penúltima pra mostrar o aninhamento em multinível
Folder.last.update(root_id: n_folders)

Barra de progresso

O download pode demorar um pouquinho dependendo da quantidade de imagens. Quis usar a gem ruby-progressbar pra entender melhor o que está acontecendo durante o rails/rake db:seed.

progressbar

Frontend

Nesse estágio do desenvolvimento eu queria ver melhor como as pastas e arquivos estavam se organizando então criei o markup e estilo do model Folder pra renderizar uma grid com toda essa estrutura.

views/folder/_index.slim

.folder
  .folder__title
    i data-feather="folder"
    span = folder.title
  .folder__items
    - folder.subfolders.each do |folder|
      / Render recursivo para mostrar infinitos níveis de pasta
      = render 'folder/index', folder: folder
    - folder.items.each do |item|
      .item
        .item__thumb style=("background-image: url(#{url_for(item.file)})" if item.file.attached?)

assets/stylesheets/components/_components.folder.sass

/// @group components
/// @name folder

.folder
  display: flex
  border: 1px solid rgba($bluegrey, .3)
  flex-direction: column
  background-color: white
  border-radius: 4px
  transition: .2s

  & &:hover
    background-color: rgba($base-grey, .5)
    border-color: $bluegrey

.folder__title
  display: flex

.folder__items
  display: grid
  grid-gap: $s
  grid-template-columns: repeat(3, minmax(0, 1fr))
  transition: .2s

  // Tratando diferentes níveis de aninhamento dentro da grid (2º nível)
  & &
    grid-template-columns: repeat(2, minmax(0, 1fr))
  
  // Tratando diferentes níveis de aninhamento dentro da grid (3º nível)
  & & &
    grid-gap: .4em

Microinterações

clickfiles

E é isso!

Estou muito grato ao time pela oportunidade de mostrar parte do meu trabalho e espero poder somar a Clicksign em breve!

Clickfiles logo

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages

  • Ruby 68.7%
  • HTML 11.3%
  • Sass 9.8%
  • JavaScript 8.2%
  • Slim 2.0%