A única razão para não usá-los para identificadores que são gerados dinamicamente é devido a questões de memória, como discutiremos a seguir.
Essa dúvida é muito comum porque muitas linguagens de programação não possuem símbolos, apenas strings e, portanto, as strings também são usadas como identificadores em seu software. Você deve se preocupar com o que os símbolos devem ser, não apenas quando você deve usar símbolos. Os símbolos são identificadores. Se você seguir essa filosofia, é provável que você faça as coisas certas.
Existem várias diferenças entre a implementação de símbolos e strings. O mais importante sobre os símbolos é que eles são imutáveis. Isso significa que eles nunca terão seu valor alterado. Por causa disso, os símbolos são instanciados mais rápido do que strings e algumas operações, como comparar dois símbolos, também são mais rápidas.
O fato de um símbolo ser imutável permite que o ruby use o mesmo objeto toda vez que você fizer referência ao símbolo, economizando memória. Portanto, a cada segunda vez que o interpretador lê: my_key, ele pode retirá-lo da memória em vez de instanciá-lo novamente. Isso é menos expansivo do que inicializar uma nova string todas as vezes.
Você pode obter uma lista de todos os símbolos já instanciados com o comando Symbol.all_symbols.
Para versões Ruby anteriores a 2.2, uma vez que um símbolo é instanciado, esta memória nunca estará livre novamente. A única maneira de liberar memória é reiniciando o aplicativo. Portanto, os símbolos também são uma das principais causas de vazamentos de memória quando usados incorretamente. A maneira mais simples de gerar um vazamento de memória é usar o método to_sym nos dados de entrada do usuário – uma vez que esses dados sempre mudarão, uma nova parte da memória será usada para sempre na instância do software. Ruby 2.2 introduziu o coletor de lixo de símbolo, que libera símbolos gerados dinamicamente, de modo que os vazamentos de memória gerados pela criação de símbolos dinamicamente não são mais uma preocupação.