2011-07-21 13 views
11

Así que aquí está mi problema.Rails String Interpolation en una cadena de una base de datos

Quiero recuperar una cadena almacenada en un modelo y en el tiempo de ejecución cambiar una parte de ella usando una variable de la aplicación de rieles. Aquí hay un ejemplo:

Tengo un modelo de mensaje, que utilizo para almacenar varios mensajes únicos. Así que diferentes usuarios tienen el mismo mensaje, pero quieren ser capaces de mostrar su nombre en el centro del mensaje, por ejemplo,

"Hi #{user.name}, ...." 

Me trataron de almacenar exactamente eso en la base de datos, pero se pone escaparon antes de mostrar en la vista o se interpola cuando se almacena en la base de datos, a través de la consola de rieles.

Gracias de antemano.

Respuesta

9

Si desea

"Hi #{user.name}, ...." 

en su base de datos, utilice comillas simples o escapar de la # con una barra invertida para mantener Rubí de la interpolación de la materia #{} inmediato:

s = 'Hi #{user.name}, ....' 
s = "Hi \#{user.name}, ...." 

Luego, más tarde, cuando desea hacer la interpolación que podría, si era temerario o confiaba en usted mismo, use eval:

s = pull_the_string_from_the_database 
msg = eval '"' + s + '"' 

Tenga en cuenta que tendrá que convertir s en una cadena de comillas dobles para que eval funcione. Esto funcionará, pero no es el enfoque más agradable y te deja abierto a todo tipo de errores extraños y confusos, pero debería estar bien siempre y cuando tú (u otras personas de confianza) estén escribiendo los hilos; Creo que estaría mejor con un simple sistema de micro-plantillas, incluso algo tan simple como esto:

def fill_in(template, data) 
    template.gsub(/\{\{(\w+)\}\}/) { data[$1.to_sym] } 
end 
#... 
fill_in('Hi {{user_name}}, ....', :user_name => 'Pancakes') 

Se puede usar cualquier delimitadores que quería, por supuesto, fui con {{...}} porque he estado usando Moustache.js y Handlebars.js últimamente. Esta implementación ingenua tiene problemas (sin opciones de formateo dentro de la plantilla, sin escapes de delimitadores, ...) pero podría ser suficiente; si sus plantillas se vuelven más complicadas, puede almacenar simplemente bits de ERB en la base de datos y usar el procesador ERB en la biblioteca estándar.

+0

Gracias, eso funcionó ... Ya estaba almacenando la cadena entre comillas. Solo me faltaba cómo interpolar después de obtenerlo de la base de datos. Soy consciente del riesgo de seguridad que conlleva usar esto, pero los usuarios no pueden cambiar esta cadena directamente. –

+0

Agregaré que si su cadena contiene HTML, use el método 'raw' (http://apidock.com/rails/ActionView/Helpers/OutputSafetyHelper/raw) frente al método' html_safe'. – dennismonsewicz

0

una manera que puedo pensar en hacer esto es tener plantillas almacenadas por ejemplo:

"nombre hi"

a continuación tienen una función en los modelos que sólo reemplaza los códigos de plantilla (nombre) con el pasado argumentos. También puede ser Usuario que ha iniciado sesión.

Debido a que esta nueva función será una parte del modelo, puede utilizarlo como cualquier otro campo de la modelo desde cualquier lugar de los carriles, incluyendo el archivo html.erb.

Espero que me ayude, avíseme si necesita más descripción.

+0

lo entiendo, creo que iba a funcionar, el problema que veo en esto es que tendría que definir todas las posibles etiquetas que podía usar y asignar cada uno a las respectivas variables/funciones dentro de la aplicación. Simplemente pensé que habría una manera más simple de hacer esto, como la interpolación de una cadena normal. –

+0

Creo que su enfoque debería funcionar también. Puede evitar que la cadena que está creando se interpola antes de almacenarse en la base de datos creando la cadena con comillas simples en lugar de comillas dobles. No estoy seguro de por qué se escapó antes de llegar a la vista. – Shaunak

+0

Estaba almacenando la versión de una sola cita, pero se transforma en una cadena doble citada escapada antes de guardarla en la base de datos. –

34

No veo un motivo para definir funciones personalizadas de ayudante de cadenas. Ruby ofrece very nice formatting approaches, p.:

"Hello %s" % ['world'] 

o

"Hello %{subject}" % { subject: 'world' } 

Ambos ejemplos devuelven "Hola mundo".

+5

Esta es la solución más elegante y simple al problema – januszm

+1

Estoy de acuerdo. Esta es la solución más simple que usa la funcionalidad existente. – CDub

0

Adición de otra posible solución utilizando Proc:

#String can be stored in the database 
string = "->(user){ 'Hello ' + user.name}" 

proc = eval(string) 

proc.call(User.find(1)) #=> "Hello Bob" 
Cuestiones relacionadas