Max Williams
Max Williams

Reputation: 32933

Safer alternative to "eval" in Ruby, for doing "un-inspect" on some strings?

I have some data values that come in from a form, which are "stringified" versions of different data types - strings, arrays, hashes etc: they're all the result of calling "inspect" on the original data.

When I get them back, i want to save them into the object again in their original pre-inspect form - ie as a hash, an array, a symbol etc.

Obviously, i could just call "eval" on each value, but this data is from a form and so is susceptible to "Bobby Tables" sql injection, or even just a Ruby call like "User.delete_all" (which is harder to police - at least Rails has some methods for sanitizing sql). It's in an admin section of the site, and only a couple of trustworthy people will ever use it, but I'd still like to find a safer way.

To make things harder, this is in Ruby 1.8.6 and Rails 2.2.2 (Just don't - I know!).

Is there a way to reverse the "inspect" method without calling eval, or is this logically the same thing? Here's some example values that I want to convert.

"\"Instrument Home\"" => "Instrument Home"
":foo" => :foo
"[\"1311089\", \"1311128\", \"1310802\"]" => ["1311089", "1311128", "1310802"]
"{:foo=>\"bar\"}" => {:foo => "bar"}

EDIT: here's what my form looks like: enter image description here

and how the form is set up:

    <% @digilearning_module.metadata_keys_and_values.each do |num, hash| %>
      <tr>
        <td><%= text_field_tag "digilearning_module[metadata_keys_and_values][#{num}][key]", hash[:key].inspect %></td>
        <td>=></td>
        <td><%= text_area_tag "digilearning_module[metadata_keys_and_values][#{num}][value]", hash[:value].inspect %></td>
      </tr>
    <% end %>

and how the data comes back in (i've omitted most of the values from the big array, for clarity).

params[:digilearning_module][:metadata_keys_and_values] = {
  "1"=>{"value"=>"[\"1311089\", \"1311128\", \"1310802\"]", "key"=>":tablet_compatible_child_mod_numbers"}, 
  "2"=>{"value"=>"\"Instrument Home\"", "key"=>":special_category"}
}

When I process this, i discard the numbers which are just there to seperate the key and value out into a hash. Then I read the keys and data values back in as the keys and values of the hash which is actually saved into the db: so for the above I would want to end up with

{:tablet_compatible_child_mod_numbers => ["1311089", "1311128", "1310802"], :special_category => "Instrument Home"}

Upvotes: 0

Views: 1032

Answers (1)

sawa
sawa

Reputation: 168081

If you don't need symbol types, then a popular way to do that that I see on Stack Overlow is to use JSON instead of Ruby objects. You can map between Ruby objects and JSON, and safely encode and decode JSON.

Upvotes: 2

Related Questions