Как преобразовать строку find_by_sql hstore в хеш в Ruby on Rails

Это кажется нелепо простым, но я не могу понять, как преобразовать хеш-строку в хеш.

Когда я делаю Answer.find_by_sql, я получаю такую ​​строку

deepthought = "\"answertolife\"=>\"42\""

Но я не могу понять, как превратить это в хэш.

Я пытался:

pry(main)> Hash[deepthought]
ArgumentError: odd number of arguments for Hash
pry(main)> JSON.parse deepthought
JSON::ParserError: 757: unexpected token at '"answertolife"=>"42"'
pry(main)> deepthought.to_json
=> "\"\\\"answertolife\\\"=>\\\"42\\\"\""

Я видел, как я могу преобразовать объект String в объект Hash?, но я до сих пор не могу понять это.

4 ответа

Решение

Rails4 поддерживает hstore из коробки, поэтому я, вероятно, буду обрабатывать приведение строк так же, как это делает Rails4. Если вы заглянете в код кастинга, специфичный для Rails4 PostgreSQL, вы найдете string_to_hstore:

def string_to_hstore(string)
  if string.nil?
    nil
  elsif String === string
    Hash[string.scan(HstorePair).map { |k, v|
      v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
      k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
      [k, v]
    }]
  else
    string
  end
end

и немного ниже в том же файле, вы найдете HstorePair:

HstorePair = begin
  quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
  unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
  /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
end

Копить, что где-то удобно (вероятно, где-то в lib/) и отправьте свои строки в hstore через это string_to_hstore распаковать их в хеши.

Немного поздно, но если вам нужно конвертировать несколько записей, это прекрасно работает.

def hstore_to_hash(hstore)
  values = {}
  hstore.gsub(/"/, '').split(",").each do |hstore_entry|
    each_element = hstore_entry.split("=>")
    values[each_element[0]] = each_element[1]
  end
  values
end

Попробуй это

eval("{ #{deepthought} }")

Оборачивает строку глубокой мысли фигурной скобкой { }, а затем использует eval

Кажется, это работает, но кажется грязным.

JSON.parse "{ #{deepthought} }".gsub('=>', ':')
Другие вопросы по тегам