a passagem de CarrierWave para ActiveStorage em uma aplicação Rails

NJ Pearman
NJ Pearman

Siga

Jun 20, 2018 · 9 min de leitura

Nós usamos Ruby on Rails para ensinar o desenvolvimento de aplicações web na EPFL Extensão da Escola. É um ótimo quadro que é sólido, experimentado e confiável e apresenta uma estrutura fácil de seguir ao dar seus primeiros passos de aprendizagem sobre o desenvolvimento da web.

mas também é um software em constante evolução, com melhorias e novos recursos sendo lançados a cada ano. Uma das recentes adições aos trilhos na versão 5.2 é o recurso ActiveStorage, que adiciona fácil gerenciamento de upload de arquivos para o core Rails framework pela primeira vez.

na primeira iteração do nosso Programa de desenvolvimento de aplicações web, incluímos um assunto para aprender a adicionar uploads de ficheiros numa aplicação de Carris. Nós usamos Rails 5.1 no programa no entanto, e o assunto de upload de arquivos usa uma das soluções de terceiros amplamente usadas para adicionar uploads de arquivos, chamado CarrierWave. Esta é uma jóia sólida de terceiros que nos permite implementar uploads de arquivos em um aplicativo Rails e está em uso em muitos aplicativos do mundo real Ruby on Rails-incluindo a nossa plataforma de aprendizagem!

mas com a introdução da ActiveStorage, estas gemas de terceiros tornam-se menos atractivas do que esta nova solução amontoada dentro dos carris. Na verdade, Paperclip, um dos outros arquivos populares de terceiros, upload gems, já anunciou que está depreciado em favor da ActiveStorage. Os desenvolvedores do Paperclip reconheceram que o ActiveStorage é uma melhor escolha para os desenvolvedores e pararam de trabalhar mais em sua própria gema.Por isso, vamos ver especificamente o que é preciso para passar da onda de carruagens nos carris 5.1 para a actividade nos carris 5.2.

a aplicação

no programa de desenvolvimento de aplicações web, trabalhamos através da construção de uma aplicação web chamada Minha Lista de desejos. Este é um aplicativo que permite aos usuários criar e acompanhar experiências que eles sempre quiseram realizar. Os usuários podem ver o que outras pessoas criaram e rastrear esses também. Uma das características do aplicativo permite que um usuário faça upload de seu próprio avatar, e nós construímos esse recurso, a fim de aprender sobre uploads de arquivos e anexos usando CarrierWave.

Um usuário pode fazer o upload de um avatar com este formulário, usando o CarrierWave

Então, primeiro, vamos dar uma rápida revisão do que está envolvido com a adição de um simples anexo usando o CarrierWave.

configuração da onda de transporte

a fim de incluir a onda de transporte num projecto, precisamos de:

  • adicione a gema da onda de Carrier ao Gemfile.
  • Include the CarrierWave adapter for ActiveRecord within a config inicializer, config/initializers/carrierwave.rb.

e, em seguida, para adicionar um anexo de imagem a um modelo, precisamos de:

  • gerar um Uploader usando rails generate uploader UploaderName.
  • adicione um atributo no modelo para armazenar o nome do ficheiro em anexo para cada registo, com a migração de base de dados associada.
  • Edite os valores no uploader, como a localização de armazenamento de upload e a imagem predefinida.
  • Use a macro mount_uploader no modelo para incluir o carregador particular.
  • adicione um campo de formulário de arquivo onde uma imagem pode ser enviada.
  • Add the model attribute to the list of strong parameters in the controller that handles the form containing the file field.

vamos considerar um destes pontos mais adiante: em CarrierWave, é necessário adicionar atributos específicos a qualquer modelo que precise ter um arquivo anexo. Por exemplo, um modelo User que necessita de uma imagem avatar ligado a ele necessitará de um atributo chamado :avatar que é um String. Isso requer uma migração de banco de dados para adicionar a coluna de banco de dados subjacente, além de criar e montar uma classe Uploader a esse atributo no modelo.

isto não é particularmente trabalhoso, mas, como veremos, ActiveStorage requer muito menos Código numa base caso a caso.

mais um ponto a destacar é que no meu aplicativo-o meu aplicativo Lista de balde-o uploader avatar carrierwave é configurado com o armazenamento de arquivos simples padrão. Em palavras de ordem, as imagens carregadas são armazenadas em algum lugar dentro da pasta public/ na aplicação. Esse caminho preciso é definido dentro da classe Uploader para o avatar, e é definido para "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}". Este é um caminho relativo à pasta public/, de modo que as imagens carregadas são diretamente acessíveis através do servidor web. Isto permite o acesso direto aos arquivos do anexo, que podemos contrastar com a ActiveStorage mais tarde.

actualizar os carris

Antes de olhar para a ActiveStorage, é necessário actualizar para os carris 5.2. Esta é uma tarefa que pode ser bastante envolvida, dependendo da complexidade de sua aplicação. A aplicação que estou usando aqui, que construímos em nosso programa WAD, não é particularmente difícil de atualizar, mas ainda precisa de algum cuidado e atenção.

aqui está o que eu fiz para atualizar a minha aplicação da lista de balde de Rails 5.1 para Rails 5.2.

primeiro, eu criei um novo branch no meu repositório git para isolar a atualização-é importante ser capaz de voltar para a versão de trabalho anterior de um aplicativo se alguma coisa correr mal no processo de atualização!

no novo ramo, alterei a versão dos carris no Gemfile de '~> 5.1.2' para '~> 5.2.0', e depois corri bin/bundle update rails — este comando descarrega a nova versão de rails e todas as pedras preciosas relacionadas na aplicação. Para a minha aplicação, não houve conflitos de gemas, mas se você estiver usando gemas de terceiros, você pode precisar resolver conflitos entre diferentes versões de gemas neste momento!

depois de instalar a nova gema Rails e suas dependências, é necessário atualizar a própria aplicação. Eu fiz isso usando bin/bundle exec rails app:update. Este comando atualiza programaticamente todos os arquivos necessários na aplicação para trabalhar com trilhos 5.2.

mas … este comando irá substituir as alterações que fez à sua aplicação, tais como config/routes.rb. Felizmente, o comando pergunta se deve sobrepor cada arquivo, e é possível diff qualquer um desses arquivos durante este processo para verificar o que seria substituído. O prompt para cada sobreposição é , o que significa:

  • Y para “Sim, sobrepor o meu ficheiro”, e é a opção por omissão se carregar em Enter.
  • n para “Não, Não sobreponha o meu ficheiro”
  • a para ” Sim, sobrepor este arquivo e sobrepor todos os outros arquivos também!”. (Minha regra geral é nunca usar a).
  • q para “sair deste processo”
  • d para “mostrar-me as diferenças entre o meu ficheiro e a sobreposição”
  • h para ” Mostre-me uma lista do que significa Ynaqdh

na minha candidatura, aceitei cada sobreposição com Y excepto config/routes.rb e config/locales/en.yml. Esses dois arquivos eram arquivos que eu tinha mudado e então eu queria manter a minha versão, então escolheu n.

este processo de actualização pode estar mais envolvido se tiver uma aplicação mais complexa, particularmente se tiver muita configuração personalizada em qualquer um dos ficheiros de configuração do ambiente. config/environments/production.rb, config/environments/test.rb, e config/environments/development.rb. A atualização adiciona configurações importantes a esses arquivos, mas você também vai querer manter a sua própria configuração personalizada — este é o lugar onde ter a versão original da aplicação em um branch git separado ajuda. É então possível ao código neste ramo antigo verificar se todo o seu código de aplicação e configuração ainda está no lugar após a atualização.

depois de correr bin/bundle exec rails app:update, foi necessário para mim adicionar a gema bootsnap ao Gemfile. Esta é uma nova jóia usada nos carris 5.2, mas não é adicionada como parte do comando app:upgrade. Então eu adicionei gem 'bootsnap' ao Gemfile e então corri bin/bundle install.

depois disto, a minha aplicação na lista de desejos começou como antes de usar rails server.

substituir a onda de Carrier por ActiveStorage

assim, com a aplicação agora a correr sobre carris 5.2, eu poderia começar a substituir a onda de Carrier por ActiveStorage.

com ActiveStorage, não é necessário adicionar atributos específicos do modelo para armazenar os nomes dos ficheiros de anexos que são necessários com CarrierWave. ActiveStorage funciona com as mesmas duas tabelas associadas para todos os anexos.

para estabelecer estes dois quadros, corri bin/bundle exec rails active_storage:install seguido de rails db:migrate. As duas tabelas são active_storage_blobs e active_storage_attachments; a primeira é para os detalhes do arquivo anexo e a segunda é para a tabela de junção polimórfica que liga um arquivo anexo a um registro modelo.

e aqui está o ponto importante: uma vez criadas essas duas tabelas, não precisamos criar quaisquer outras migrações para incluir anexos em nossos modelos! Isto torna a ActiveStorage fácil de trabalhar numa perspectiva de base de dados.

Next, I looked at replacing the implementation of the :avatar attachment with ActiveStorage instead of CarrierWave. Na minha aplicação, cada User tem um :avatar. Como eu estava usando CarrierWave anteriormente, eu tinha um atributo :avatar montado em uma CarrierWave Uploader no modelo User, declarado assim:

class User < ApplicationRecord
# ... various codez mount_uploader :avatar, AvatarUploader # ... other codez
end

a canícula :avatar pode ser substituída por um acessório ActiveSupport, usando has_one_attached :avatar, assim:

class User < ApplicationRecord
# ... various codez # commented old uploader for reference
# mount_uploader :avatar, AvatarUploader
has_one_attached :avatar # ... other codez
end

isso é uma mudança para uma linha de código. Neste momento, o que mais precisa ser feito? Por exemplo, como é o local de armazenamento de upload definido? Lembre-se que no meu aplicativo, o uploader avatar CarrierWave é configurado com o armazenamento de arquivos simples padrão, e a localização para isso é explicitamente definido no arquivo avatar_uploader.rb. Armazenamento de arquivos simples é o padrão na ActiveStorage também. A localização é definida dentro do arquivo config/storage.yml, com um valor padrão para uploads locais.

a configuração padrão para ActiveStorage significa que não preciso de escrever mais nenhum código para as minhas uploads para trabalhar para o atributo :avatar modificado na minha aplicação. Mudei o mecanismo de upload de CarrierWave para ActiveStorage e não preciso de fazer mais nada.: Eu não preciso fazer quaisquer alterações no controlador que gerencia o upload, porque :avatar já é declarado como um parâmetro forte. E eu não preciso mudar o campo de formulário de arquivo na janela que permite aos usuários selecionar uma imagem para carregar, porque isso é suportado pelo atributo :avatar.

mas há mais uma mudança que eu preciso fazer para migrar de CarrierWave para ActiveStorage, e que é como usar a imagem anexada em vistas. Com CarierWave, usei o método avatar_url para desenhar o caminho completo da imagem. Com o ActiveStorage, o URL do arquivo não é renderizado a partir do atributo do anexo em si, mas renderizado passando o atributo para os métodos auxiliares. Assim, o URL completo do anexo pode ser renderizado usando url_for(user.avatar), ou diretamente com image_tag.

também é necessário verificar explicitamente se o anexo está presente, para que uma utilização completa numa vista se pareça com isto:

<% if current_user.avatar.attached? %>
<%= image_tag current_user.avatar, class: 'avatar' %>
<% else %>
<%= image_tag 'default-avatar', class: 'avatar' %>
<% end %>

uma vez que atualizei as referências para o user.avatar_url em meus pontos de vista com trechos como aquele acima, eu tinha mudado completamente de CarrierWave para Ativestorage para todos os novos uploads.

o antigo código de onda de Carrier precisa ser arrumado, e há uma questão sobre o que fazer com quaisquer uploads existentes que foram feitos com CarrierWave. Mas veja abaixo sobre isso …

cenários mais complexos

quase todos os cenários de produção serão mais complexos do que o acima descrito. Será necessário considerar coisas como uploads sendo armazenados em CDNs ou servidores remotos como AWS S3, e dimensionamento de imagens para miniaturas, etc. ActiveStorage nos permite fazer muitas dessas coisas fora da caixa também e parece muito bem projetado para as necessidades dos desenvolvedores. Como você pode esperar, há boa documentação no Guia de trilhos.

no que diz respeito à migração de uploads existentes de CarrierWave para ActiveStorage, isso certamente seria possível com um rake script relativamente pequeno. Vou procurar cobrir isso num futuro cargo.

este era um cenário simples, mas no geral eu estava realmente satisfeito com o quão fácil era fazer uso de ActiveStorage e substituir CarrierWave com ele. Eu também gosto do pensamento que foi para as várias partes da ActiveStorage, como tudo parece estar em arquivos e pastas que combinam muito bem com a estrutura do resto dos trilhos. Eu definitivamente acho que vale a pena entrar em Rails 5.2, A fim de usar o ActiveStorage para uploads de arquivos em suas aplicações!

Saiba mais!Interessado em aprender mais sobre Ruby, e Ruby on Rails? Eu ensino desenvolvimento de aplicações Web na EPFL extensão escola, uma plataforma de aprendizagem online certificada ensinando habilidades digitais em ciência de dados, desenvolvimento de aplicações web, e muito mais. A EPFL é uma das principais universidades do mundo e é classificada como a “Universidade número 1 Jovem” pelo ranking do Times Higher Education.



+