Armazenar credenciais do Amazon S3 em variáveis ambientais .bashrc causa falha no aplicativo Rails
-
20-09-2019 - |
Pergunta
Estou desenvolvendo um aplicativo Rails que usa clipe de papel para armazenar coisas no Amazon S3.O aplicativo está hospedado no Heroku.Estou desenvolvendo no Ubuntu Karmic.
O problema que estou prestes a descrever ocorre no desenvolvimento (no meu host local) e na produção (no Heroku).
A maneira padrão de passar credenciais S3 para o clipe de papel é colocá-los em config/s3.yml assim:
access_key_id: 12345678
secret_access_key: 903490409fdf09fshsfdoif/43432
Quando faço isso, tudo funciona bem.Mas isso dificulta o compartilhamento do meu código com outras pessoas, então o Heroku sugere um método alternativo - http://docs.heroku.com/config-vars.
Eles aconselham que você coloque S3_KEY e S3_SECRET em seu .bashrc assim:
S3_KEY=12345678
export S3_KEY
S3_SECRET=903490409fdf09fshsfdoif/43432
export S3_SECRET
Eles então sugerem que você crie config/initializers/s3.yml (observe o caminho ligeiramente diferente) e coloque o seguinte nesse arquivo:
AWS::S3::Base.establish_connection!(
:access_key_id => ENV['S3_KEY'],
:secret_access_key => ENV['S3_SECRET']
)
MAS, quando faço isso, o clipe de papel oscila e cospe a seguinte mensagem de erro:
undefined method `stringify_keys' for #<String:0xb6d6c3f4>
/vendor/plugins/paperclip/lib/paperclip/storage.rb:176:in `parse_credentials'
/vendor/plugins/paperclip/lib/paperclip/storage.rb:138:in `extended'
/vendor/plugins/paperclip/lib/paperclip/storage.rb:137:in `instance_eval'
/vendor/plugins/paperclip/lib/paperclip/storage.rb:137:in `extended'
.... other stuff
Claramente, tudo está começando dentro do módulo storage.rb.Percorrendo o rastreamento de pilha:
O método parse_credentials na linha 176 está sinalizado - aqui está a chamada conforme aparece no código:
def parse_credentials creds
creds = find_credentials(creds).stringify_keys
(creds[RAILS_ENV] || creds).symbolize_keys
end
O método parse_credentials tenta chamar outro método, find_credentials, e é aí que acredito que esteja o problema.Aqui está o código para find_credentials:
def find_credentials creds
case creds
when File
YAML::load(ERB.new(File.read(creds.path)).result)
when String
YAML::load(ERB.new(File.read(creds)).result)
when Hash
creds
else
raise ArgumentError, "Credentials are not a path, file, or hash."
end
end
Não consigo ver como o método find_credentials está equipado para ler valores do meu arquivo .bashrc.Tem dois casos em que pode ler YAML e um em que procura um hash.
Meu modelo faz referência às credenciais da seguinte forma:
has_attached_file :photo,
(some code removed)
:s3_credentials => "#{RAILS_ROOT}/config/initializers/s3.yml",
Se eu remover o hash :s3_credentials do modelo, o erro stringify_keys desaparece e o console rails lança a mensagem de erro que aparece no final do método find_credentials:ou seja"Credenciais não são um caminho, arquivo ou hash".
Então estou perplexo.Eu percebo que esta é possivelmente uma pergunta para o pessoal do Heroku (para quem vou enviar este link por e-mail na esperança de que eles possam respondê-la) e também é possivelmente uma pergunta para os doods do Thoughtbot.
Como eu disse no início, meu aplicativo funciona bem quando eu adoto a abordagem padrão de inserir minha chave e segredo em config/s3.yml, mas eu preferiria usar o método sugerido pelo Heroku porque torna as coisas MUITO mais fáceis para mim e isso significa que posso armazenar meu repositório em minha página pública do github para que outros possam usá-lo, sem precisar escrever nenhum driver de mesclagem de cliente no Git para manter minhas chaves de API fora do domínio público.
Tentei inserir as variáveis ENV em etc/bash.bashrc e também em ~/.bashrc e após reiniciar, ainda tenho o mesmo problema.Os problemas ocorrem tanto na máquina de desenvolvimento quanto no Heroku.Certifiquei-me de enviar meus config-vars para o Heroku também.
Solução
Depois de muito pesquisar encontrei a resposta aqui - http://tammersaleh.com/posts/managing-heroku-environment-variables-for-local-development
O truque é remover completamente o arquivo S3.rb e apenas consultar as variáveis ENV no modelo assim:
has_attached_file :photo,
#...
:storage => :s3,
:bucket => ENV['S3_BUCKET'],
:s3_credentials => { :access_key_id => ENV['S3_KEY'],
:secret_access_key => ENV['S3_SECRET'] }
De qualquer forma, David, obrigado pela sua sugestão.Não sei se você deseja atualizar a documentação do Heroku para dizer que alguns usuários tiveram que fazer isso dessa maneira.Obrigado novamente.
Outras dicas
Renomeie o arquivo config/initializers/s3.yml
para config/initializers/s3.rb
e experimente.
Aqui está o seu problema:
:bucket => ENV['S3_BUCKET'],
precisa ser
:bucket => <%= ENV['S3_BUCKET'] %>,
ou sejaas atribuições não estão sendo interpretadas.