LINUX.ORG.RU

ruby+postgresql, затык с кавычками

 ,


1

1

В postgres одинарные кавычки используются для строковых типов данных в полях, а двойные - для имен таблиц и полей. В ruby одинарные кавычки используются для «простых» строк, спец. символы в них экранируются автоматически. А двойные - для строк с исполняемыми фрагментами кода. Исполняемый фрагмент оформляется, например, так

"#{переменная}"

В базе есть такая запись

name | num | command
-------+-----+-----------------------------------
a7324 | 1 | statistics adsl linerate #{@port}

Команда должна извлечься запросом и выполниться telnet'ом с переменной @port, но из-за одинарных кавычек решетка экранируется и команда не работает.
Как быть в такой ситуации?

Лайфхак:

#irb
irb(main):001:0> class String
irb(main):002:1>   def substitute(binding=TOPLEVEL_BINDING)
irb(main):003:2>     eval(%{"#{self}"}, binding)
irb(main):004:2>   end
irb(main):005:1> end
=> nil
irb(main):006:0> @port = 1234
=> 1234
irb(main):007:0> mystr = 'statistics adsl linerate #{@port}'
=> "statistics adsl linerate \#{@port}"
irb(main):008:0> mystr.substitute
=> "statistics adsl linerate 1234"
melkor217 ★★★★★ ()
Последнее исправление: melkor217 (всего исправлений: 2)
Ответ на: комментарий от melkor217

И да, минздрав предупреждает - ты хочешь странного и не безопасного.

melkor217 ★★★★★ ()
Ответ на: комментарий от theNamelessOne

Одинарные кавычки добавлял .to_s, который я применял на элемент массива (т.к. gem telnet работает только со строками). После замены .to_s на .join экранирование пропало, но интерполяция не работает.

hasculdr ()
Ответ на: комментарий от hasculdr

После замены .to_s на .join экранирование пропало, но интерполяция не работает.

Ещё раз:

Строковая интерполяция работает только с литералами.

Ты из базы получаешь не литералы.

theNamelessOne ★★★★★ ()

но из-за одинарных кавычек решетка экранируется

ничего не экранируется на самом деле, ты получаешь строку как есть

irb(main):008:0> a = '123 #{@port} 123'
=> "123 \#{@port} 123"
irb(main):009:0> puts a
123 #{@port} 123
=> nil
melkor217 ★★★★★ ()

У тебя в базе по сути код на руби, его выполнить только eval может. Храни лучше некий шаблон, а потом подставляй в него что нужно. Для простых случаев юзай Kernel#format, для тяжелых erb (хотя это перебор, лучше уж накостылить свой микрошаблонизатор).

anonymous ()
Ответ на: комментарий от theNamelessOne

Строковая интерполяция работает только с литералами.

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

anonymous ()
Ответ на: комментарий от anonymous

Не совсем точно, работает то она с любым выражением

Ну например?

на уровне разбора исходного кода

А сколько ещё уровней?

melkor217 ★★★★★ ()
Ответ на: комментарий от anonymous

Не совсем точно, работает то она с любым выражением

Это как?

theNamelessOne ★★★★★ ()
Ответ на: комментарий от anonymous

для тяжелых erb (хотя это перебор, лучше уж накостылить свой микрошаблонизатор)

Тем более erb тоже не полностью безопасен.

theNamelessOne ★★★★★ ()

Пиши в базу так:

command = 'statistics adsl linerate %<port>s'

А потом используй String#format:

blabla(format(command, @options))

Где @options — хэш с параметрами вида {port: "123", …}.

spijet ★★★ ()
Ответ на: комментарий от theNamelessOne

Можно и так, да, просто вариант со спецификатором мне привычнее. :)

spijet ★★★ ()
Ответ на: комментарий от hasculdr

Только учти, если у тебя записи («команды») в базе создаёт обычный пользователь, то использовать erb или eval — значит создавать дыру в безопасности.

theNamelessOne ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.