https://a.storyblok.com/f/270183/51864/d3b8b6b818/environment-variables_ruby.png

Trabalhando com variáveis de ambiente em Ruby

Publicado em November 14, 2023

Tempo de leitura: 10 minutos

Ao trabalhar com aplicativos web, os desenvolvedores precisam lidar com diversos componentes. Na maioria das vezes, não paramos para pensar sobre quais são esses componentes individualmente e como exatamente eles funcionam. Neste artigo, vamos explorar apenas um desses componentes: variáveis de ambiente.

Se você já desenvolveu e implantou uma aplicação web em Ruby, provavelmente já utilizou variáveis de ambiente. Se essa aplicação foi desenvolvida com Ruby on Rails, então você precisou definir RAILS_ENV durante 'production' durante o processo de implantação. Se a aplicação integrasse serviços externos ou APIs, provavelmente você teria usado variáveis de ambiente para gerenciar as credenciais desses serviços.

Mas o que exatamente são variáveis de ambiente, por que elas são úteis e como podemos aproveitá-las ao desenvolver e implantar Applications em Ruby?

O que são variáveis de ambiente?

Como o nome sugere, variáveis de ambiente são variáveis que armazenam informações sobre o ambiente em que nosso aplicativo opera. Você provavelmente já está familiarizado com o conceito de variáveis e como elas funcionam; portanto, vamos examinar um pouco mais de perto essa segunda parte: o ambiente.

Nesse contexto, o termo “ambiente” pode se referir ao sistema operacional no qual seu programa é executado, mas também pode se referir ao processo — ou aos processos — utilizados para executar o programa. Isso talvez fique um pouco mais claro se analisarmos alguns exemplos.

Quando você abre uma janela do Terminal no seu computador, isso inicia um processo do Shell. O Shell é, essencialmente, um programa que permite que você interaja com o sistema, processando comandos emitidos por meio dele e exibindo o resultado. Por exemplo, ao iniciar uma aplicação Rails na sua máquina local, você digita um comando como rails s e vê um resultado mais ou menos assim:

=> Booting Puma
=> Rails 7.0.4.3 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.6.5 (ruby 3.0.0-p0) ("Birdie's Version")
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 126917
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop

Esse processo, o Shell, possui informações sobre o ambiente em que é executado e armazena essas informações em variáveis. Os processos herdam uma cópia das variáveis de ambiente de seu processo pai; portanto, o Shell possui uma cópia das variáveis de ambiente do sistema operacional (ou, mais especificamente, do kernel). Da mesma forma, qualquer processo executado no Shell herdará uma cópia das variáveis de ambiente desse Shell.

Acesso às variáveis de ambiente

Em sistemas baseados em UNIX (por exemplo, Linux e OS X), é possível acessar todas as variáveis de ambiente do Shell usando o env . O Windows possui um comando equivalente set , mas, para os fins deste artigo, abordaremos apenas os comandos usados em sistemas baseados em UNIX.

Se você quiser exibir uma variável de ambiente específica, pode usar o printenv comando. Por exemplo, se eu quisesse verificar o idioma que configurei no meu sistema, poderia digitar o printenv comando seguido do nome da variável de ambiente que contém esses dados; neste caso, LANG. Isso exibirá o idioma, que no meu sistema é en_GB.UTF-8:

$ printenv LANG
en_GB.UTF-8

Um exemplo mais específico do Ruby seria RUBY_VERSION:

$ printenv RUBY_VERSION
ruby-3.2.2

Se você fosse executar um processo Ruby a partir do Shell, essa seria a versão do Ruby que o processo utilizaria. Se você tiver um gerenciador de versões do Ruby instalado, como chruby, rbenvou rvm, tente executar o printenv RUBY_VERSION em seguida, altere sua versão do Ruby com seu gerenciador de versões e execute printenv RUBY_VERSION novamente. Você deverá ver a versão do Ruby para a qual acabou de mudar.

Por falar em processos Ruby, podemos acessar variáveis de ambiente de dentro de um programa Ruby por meio do objeto ENV . Conforme a explica a documentação do Ruby explica:

ENV é um acessador semelhante a um hash para variáveis de ambiente.

A ENV classe possui vários métodos diferentes que permitem interagir com os valores armazenados em um ENV objeto. Para os fins deste artigo, estamos interessados apenas em acessar valores usando a notação entre colchetes, mas fique à vontade para explorar o restante das funcionalidades descritas na documentação do Ruby.

Podemos acessar o valor de uma variável de ambiente por meio do ENV usando a notação entre colchetes, da mesma forma que acessaríamos valores de um Hash do Ruby, utilizando o nome da variável de ambiente como chave.

ENV['RUBY_VERSION'] # => ruby-3.2.2

Observe que a variável name é passada RUBY_VERSION, como uma String entre ENV parênteses.

Vamos testar isso no nosso Shell:

$ printenv RUBY_VERSION
ruby-3.2.2
$ ruby -e "puts ENV['RUBY_VERSION']"
ruby-3.2.2

No exemplo acima, primeiro usamos o printenv para exibir o valor da variável de ambiente RUBY_VERSION , que é ruby-3.2.2. Em seguida, invocamos o ruby comando com a -e opção. Isso instrui o interpretador do Ruby a não executar a string que passamos a ele como código Ruby. Esse código Ruby exibe o valor associado ao ENV chave do objeto RUBY_VERSION chave. Como podemos ver, o valor 'RUBY_VERSION' dentro do processo Ruby é o mesmo que o valor RUBY_VERSION dentro de seu processo pai do Shell.

Definição de variáveis de ambiente

Até agora, exploramos apenas como acessar variáveis de ambiente já existentes. No entanto, elas se tornam ainda mais úteis quando você começa a definir as suas próprias.

Em um shell baseado em UNIX, as variáveis de ambiente podem ser definidas usando o export comando combinado com a sintaxe de atribuição:

$ export FOO=bar
$ printenv FOO
bar

Assim como acontece com as variáveis de ambiente pré-existentes, aquelas que você cria dentro de um processo também são herdadas por quaisquer processos filhos. Mais uma vez, podemos testar isso dentro de um processo Ruby.

$ export FOO=bar
$ printenv FOO
bar
$ ruby -e "puts ENV['FOO']"
bar

É importante observar que os processos irmãos mantêm suas próprias cópias das variáveis de ambiente, em vez de compartilhá-las. Se você abrir uma segunda janela do Terminal e executar printenv FOO, nada será exibido.

Da mesma forma, as variáveis de ambiente criadas dentro de um processo são encerradas junto com esse processo. Por exemplo, se você executar export FOO=bar, fechar a janela do Terminal, abrir uma nova janela do Terminal e executar printenv FOO, nada será exibido.

Por que usar variáveis de ambiente?

Um dos principais usos das variáveis de ambiente é definir dados de configuração durante o desenvolvimento ou a implantação de uma aplicação. Um exemplo comum disso é a definição de credenciais de API ao utilizar um serviço externo, como o APIs da Vonage Communications.

Digamos, por exemplo, que você tenha um arquivo Ruby chamado send_sms.rb. O código nesse arquivo envia um SMS por meio da SMS API de Vonage usando o SDK do Ruby da Vonage. Para autenticar sua solicitação à SMS API da Vonage, você precisa instanciar um Vonage::Client objeto com um api_key e api_secret.

client = Vonage::Client.new(api_key: 'abc123', api_secret: 'ab1CDef2GhIjkLmn')

client.sms.send(from: 'Ruby', to: '447700900000', text: 'Hello world')

Geralmente, não é recomendável codificar essas credenciais diretamente no código-fonte dessa forma. Provavelmente, você enviará esse código para um serviço de controle de versão como o GitHub; mesmo que o repositório não seja público, não é uma boa ideia expor suas credenciais de API no histórico do Git. Além disso, é bem possível que você use credenciais de API diferentes no ambiente de desenvolvimento e no de produção (e possivelmente também em outros ambientes, como o de teste ou o de controle de qualidade). As variáveis de ambiente podem ser atualizadas entre as implantações sem a necessidade de modificar o código-fonte.

No contexto de uma aplicação em Ruby, é aqui que podemos aproveitar o ENV . Nosso send_sms.rb pode ficar mais ou menos assim:

client = Vonage::Client.new(api_key: ENV['VONAGE_API_KEY'], api_secret: ENV['VONAGE_API_SECRET'])

client.sms.send(from: 'Ruby', to: '447700900000', text: 'Hello world')

Você poderia então usar export para definir VONAGE_API_KEY e VONAGE_API_SECRET como variáveis de ambiente:

$ export VONAGE_API_KEY=abc123 VONAGE_API_SECRET=ab1CDef2GhIjkLmn

Quando você executar posteriormente o send_sms.rb arquivo, o ENV objeto no processo Ruby que estiver executando o código terá acesso às variáveis de ambiente que você definiu.

$ ruby send_sms.rb

A título de observação, se você não for aprovado no api_key e api_secret argumentos de palavra-chave para Vonage::Client.new, quando necessário, o SDK Ruby da Vonage verificará automaticamente o ENV objeto em busca de variáveis de ambiente chamadas VONAGE_API_KEY e VONAGE_API_SECRET. Desde que você tenha essas variáveis de ambiente definidas ao usar APIs da Vonage que exijam uma chave de API e um segredo para autenticação, você poderá instanciar o Vonage::Client objeto desta forma:

client = Vonage::Client.new

Quer ver isso em ação em um aplicativo Rails? Confira nosso tutorial sobre envio de SMS com Ruby on Rails usando variáveis de ambiente para as credenciais do Vonage.

Como usar variáveis de ambiente

Nos exemplos até agora, você usou export para definir suas variáveis de ambiente. Fazer isso toda vez que você executa um processo Ruby em um novo Shell ou ambiente pode se tornar um pouco trabalhoso, especialmente se você tiver um grande número de variáveis de ambiente para definir. Felizmente, existem outras soluções disponíveis tanto para desenvolvimento quanto para produção.

Em desenvolvimento

Uma ótima opção para desenvolvimento é a dotenv biblioteca. Trata-se de um RubyGem que você pode incluir em seu Gemfile ou instalar localmente. Para usá-la, você precisa criar um .env arquivo na raiz do seu projeto Ruby. Nesse arquivo, você define as variáveis de ambiente necessárias para sua aplicação como pares chave-valor.

VONAGE_API_KEY=abc123
VONAGE_API_SECRET=ab1CDef2GhIjkLmn

Na sua aplicação em Ruby, você pode então require a gem e chamar o load método na Dotenv classe. Isso carrega todas as variáveis de ambiente definidas no seu .env arquivo no ENV objeto do processo Ruby atual.

require 'dotenv'
Dotenv.load

client = Vonage::Client.new(api_key: ENV['VONAGE_API_KEY'], api_secret: ENV['VONAGE_API_SECRET'])

client.sms.send(from: 'Ruby', to: '447700900000', text: 'Hello world')

Há também um dotenv-rails gem incluída como parte da biblioteca, que é específica para uso com aplicativos Rails. O uso é um pouco diferente do dotenv gem padrão, mas o conceito é o mesmo.

A biblioteca possui algumas outras funcionalidades, que não abordarei aqui, mas você pode ler sobre elas na documentação.

Um último ponto a ser destacado aqui, seja usando dotenv ou dotenv-rails você deve sempre se certificar de adicionar seu .env arquivo ao .gitignore para que ele não seja incluído no seu repositório Git.

Se você estiver desenvolvendo um aplicativo Rails que precise de testes de webhooks, provavelmente vai querer usar o ngrok junto com o dotenv. Confira nosso guia de configuração do Rails + ngrok para um passo a passo completo.

Em produção

Embora, de acordo com a documentação que você pode usar dotenv em produção, outras ferramentas e opções são mais adequadas para gerenciar variáveis de ambiente em produção.

  • Ferramentas de gerenciamento de configuração, como Chef, Puppete Ansible são opções poderosas e completas. Essas ferramentas provavelmente são mais adequadas para trabalhar em grande escala, mas podem ser exageradas para projetos menores, caso você queira apenas definir algumas variáveis de ambiente.

  • Uma solução de conteinerização como Docker oferece uma maneira específica de lidar com variáveis de ambiente para dados confidenciais, como chaves de API.

  • Se você estiver usando um serviço como Render ou Heroku para implantar e hospedar suas aplicações em Ruby, geralmente é possível definir suas variáveis de ambiente como pares chave-valor na interface de usuário fornecida pelo serviço, seja para uma única aplicação ou para um grupo de aplicações (veja a captura de tela abaixo). Algumas variáveis de ambiente comumente usadas podem até mesmo ser definidas automaticamente para você; por exemplo, o Render define automaticamente RAILS_ENV como production para aplicativos Ruby.

Screenshot of the Render Dashboard for adding environment variables, showing a form with 'key' and 'value' fieldsRender Environment Variable form

Uma breve nota sobre as credenciais do Rails

Se você estiver trabalhando especificamente com o Rails, uma alternativa ao uso de variáveis de ambiente é utilizar Credenciais do Rails, embora esse seja um assunto para outro post no blog!

Conclusão

Por enquanto é só! Espero que tenham achado este artigo interessante e informativo.

Se você estiver pronto para ver como as variáveis de ambiente podem impulsionar uma experiência real de mensagens, confira este tutorial sobre como enviar respostas sugeridas por RCS com Ruby on Rails. Ele mostra como combinar a configuração do ambiente, o Rails e a Messages API do Vonage em um caso de uso prático.

Tem alguma dúvida ou quer compartilhar o que está criando?

Fique conectado e acompanhe as últimas notícias, dicas e eventos para desenvolvedores.

Compartilhar:

https://a.storyblok.com/f/270183/373x376/e8d3211236/karl-lingiah.png
Karl LingiahDefensor da Comunidade de Desenvolvedores Ruby

Karl é um Developer Advocate da Vonage, com foco na manutenção de nossos SDKs de servidor em Ruby e na melhoria da experiência dos desenvolvedores da nossa comunidade. Ele adora aprender, criar coisas, compartilhar conhecimento e tudo o que esteja relacionado à tecnologia da web em geral.