2017-01-11 8 views
1

Я использую enum для сопоставления целых чисел в моей базе данных с семантическими значениями в моем рубиновом коде, однако я заметил, что ключи, которые он использует, являются строками. Когда я проверил тип хеша, я обнаружил, что это ActiveSupport::HashWithIndifferentAccess, а не стандартный Hash, что имеет смысл, но приводит к вопросу о том, почему Rails решил хранить и сравнивать значения как строки, а не символы внутри.Почему ключи Rails `HashWithIndifferentAccess` хранятся в виде строк, а не символов?

В documentation состояния:

Внутренне символы отображаются в строках, когда используются в качестве ключей в целом интерфейс написания

Символы, как правило, используются в хэшей из-за их быстрого сравнения, но Rails имеет вместо этого используется вместо них. Почему они решили сделать это и насколько значительна разница в производительности?

ответ

3

Почему они выбрали, чтобы сделать это

ActiveSupport::HashWithIndifferentAccess в основном используется для обработки параметров, поступающих извне. Символы хранятся в рубиновой куче, и в целом они никогда не выпускаются обратно в систему.

Использование символов как ключей в чем-то, что получает ключи снаружи, приводит к уязвимости против атак OutOfMemory ([D]DoS, отправляя запросы с произвольно сгенерированными именами параметров.) Вот почему были выбраны строки AFAIU. Для 100% гарантии спросите DHH.

Насколько значительна разница в производительности?

Используйте Benchmark для проверки. Этот сайт не должен быть сайтом «Пожалуйста, сделайте тесты для меня».

+2

Btw символы теперь GCed в Ruby 2.4.0. – ndn

+0

@ndn, если их длина больше или равна 24 байтам, они хранятся в 'RValue', которые ** не ** GC'ed. Google для «рубиновых куч». Возможно, это тоже было изменено в Ruby 2.4, но я в этом сомневаюсь. – mudasobwa

3

В прошлом существовали некоторые реализации, которые не могли собирать символы. IOW, символ, однажды созданный, останется в памяти до конца времени процесс (который для серверного процесса, такого как приложение Rails, может составлять несколько месяцев). До трех недель назад YARV, самая популярная реализация, оказалась одной из них.

Ergo, вы можете сделать систему Ruby одной из этих уязвимых реализаций, создав множество символов, и поскольку Rails использует HWIA для параметров запроса (которые полностью находятся под контролем атакующего), среди прочего, это довольно тривиально Сделай так.

Теперь, когда каждая реализация поддерживает сбор символов (JRuby и Rubinius поддерживали ее много лет назад, YARV поддерживает ее с версии 2.4.0), стратегия реализации может измениться ... или нет: никогда не изменяйте запущенную систему.