Why Is This String Key in a Hash Converted to a Symbol

Best way to convert strings to symbols in hash

In Ruby >= 2.5 (docs) you can use:

my_hash.transform_keys(&:to_sym)

Using older Ruby version? Here is a one-liner that will copy the hash into a new one with the keys symbolized:

my_hash = my_hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}

With Rails you can use:

my_hash.symbolize_keys
my_hash.deep_symbolize_keys

How do I prevent string keys from being converted to symbols in Rails?

If you want that, the correct syntax is changing : to => like this:

 my_hash_arr = [{"name" => "DA", "amount" => 100000 }]
=> [{"name"=>"DA", "amount"=>100000}]

Unwanted symbol to string conversion of hash key

It may end up as a HashWithIndifferentAccess if Rails somehow gets ahold of it, and that uses string keys internally. You might want to verify the class is the same:

assert_equal Hash, assigns(:my_hash).class

Parameters are always processed as the indifferent access kind of hash so you can retrieve using either string or symbol. If you're assigning this to your params hash on the get or post call, or you might be getting converted.

Another thing you can do is freeze it and see if anyone attempts to modify it because that should throw an exception:

@my_hash = { :my_key => :my_value }.freeze

Why would one use String keys for a hash over symbols

Because the source of the keys--the query string--is made up of strings, so searching through this string for keys, it is most directly convenient to index the hash via the strings.

Every Symbol that is created in the Ruby runtime is allocated and never released. There is a theoretical (but unlikely) DOS attack available by sending hundreds of thousands of requests with unique query string parameters. If these were symbolized, each request would slowly grow the runtime memory pool.

Strings, on the other hand, may be garbage collected. Thousands of unique strings handled across various requests will eventually go away, with no long-term impact.

Edit: Note that with Sinatra, symbols are also available for accessing the params hash. However, this is done by creating a hash that is indexed by strings, and converting symbols (in your code) to strings when you make a request. Unless you do something like the following:

params.each{ |key,_| key.to_sym }

...you are not at risk of any symbol pseudo-DOS attack.

String as key being converted into symbol giving different behavior in rails

I'm not sure of any reason why the string keys would be "automatically" converted to symbols - probably there's some code in your application which does this. However you can deal with it pretty easily

for example you can use Hash#with_indifferent_access

# this will work even with symbol keys
on, direction = sort.with_indifferent_access.values_at "on", "direction"

Or you can use Hash#stringify_keys (there's also Hash#symbolize_keys for what it's worth, although you wouldn't need that here.)

on, direction = sort.stringify_keys.values_at "on", "direction"

If you were using plain Ruby (not Rails) and didn't want to include ActiveSupport (which provides with_indifferent_access and stringify_keys), there are options as well:

You could use Hash#transform_keys which used to be Rails-only, but is in Ruby core since 2.5:

on, direction = sort.transform_keys(&:to_s).values_at "on", "direction"

Or each_with_object / reduce

Hash key access via symbol not string

Because 'key' is a String and :key is a Symbol - those are two different things in Ruby.

It can be somewhat confusing, because :'key', or 'key': will also be a Symbol To make it work, just access Hash fields with a Symbol, like:

if (auth[:user])

To convert String indexed Hash to Symbol indexed Hash, refer to this question:

Best way to convert strings to symbols in hash

Rails using Symbol vs String as key in params hash

The reason used to be security. It's no longer relevant in Ruby 2.2 or later.

Before Ruby 2.2 symbols were not garbage collected. This means that once a symbol was created via a literal (:my_symbol) or #to_sym it would be around forever.

If Rails used symbols instead of strings then it would create symbols corresponding to names of params in a request. An attacker could send requests with params named param1, param2, ... and exhaust server memory by making the app allocate hundreds of thousands of symbols.

It's no longer the case in Ruby 2.2 or later

Why use symbols as hash keys in Ruby?

TL;DR:

Using symbols not only saves time when doing comparisons, but also saves memory, because they are only stored once.

Ruby Symbols are immutable (can't be changed), which makes looking something up much easier

Short(ish) answer:

Using symbols not only saves time when doing comparisons, but also saves memory, because they are only stored once.

Symbols in Ruby are basically "immutable strings" .. that means that they can not be changed, and it implies that the same symbol when referenced many times throughout your source code, is always stored as the same entity, e.g. has the same object id.

Strings on the other hand are mutable, they can be changed anytime. This implies that Ruby needs to store each string you mention throughout your source code in it's separate entity, e.g. if you have a string "name" multiple times mentioned in your source code, Ruby needs to store these all in separate String objects, because they might change later on (that's the nature of a Ruby string).

If you use a string as a Hash key, Ruby needs to evaluate the string and look at it's contents (and compute a hash function on that) and compare the result against the (hashed) values of the keys which are already stored in the Hash.

If you use a symbol as a Hash key, it's implicit that it's immutable, so Ruby can basically just do a comparison of the (hash function of the) object-id against the (hashed) object-ids of keys which are already stored in the Hash. (much faster)

Downside:
Each symbol consumes a slot in the Ruby interpreter's symbol-table, which is never released.
Symbols are never garbage-collected.
So a corner-case is when you have a large number of symbols (e.g. auto-generated ones). In that case you should evaluate how this affects the size of your Ruby interpreter.

Notes:

If you do string comparisons, Ruby can compare symbols just by comparing their object ids, without having to evaluate them. That's much faster than comparing strings, which need to be evaluated.

If you access a hash, Ruby always applies a hash-function to compute a "hash-key" from whatever key you use. You can imagine something like an MD5-hash. And then Ruby compares those "hashed keys" against each other.

Every time you use a string in your code, a new instance is created - string creation is slower than referencing a symbol.

Starting with Ruby 2.1, when you use frozen strings, Ruby will use the same string object. This avoids having to create new copies of the same string, and they are stored in a space that is garbage collected.

Long answers:

https://web.archive.org/web/20180709094450/http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings

http://www.randomhacks.net.s3-website-us-east-1.amazonaws.com/2007/01/20/13-ways-of-looking-at-a-ruby-symbol/

https://www.rubyguides.com/2016/01/ruby-mutability/



Related Topics



Leave a reply



Submit