2010-09-21 39 views
30

No tengo problemas para realizar llamadas AJAX típicas hacia y desde Rails (3) con objetos JSON y jQuery-rails (biblioteca jQuery más un archivo especial rails.js).Manejo de JSON en plantilla JS/ERB en Rails 3

En un controlador, sin embargo, deseo DEVOLVER algunos JSON en una plantilla erb (create.js.erb) después de una llamada AJAX.

He intentado todas las combinaciones de cosas en el controlador (@ object.to_json, '[{"content": "hello world"}]', etc.) y en la propia plantilla (JSON.parse() , comillas simples, comillas dobles, etc.), pero el objeto sigue haciendo de esta manera:

'[{"groups":{},"created_at":"2010-09-21T03:49:34Z" ... 

y, como resultado, mi código jQuery no puede analizarlo y me da errores.

¿Cómo necesito preparar mi objeto en el controlador y qué sintaxis erb necesito en la vista para que se muestre como un objeto JSON válido?

Gracias tanto!

Respuesta

51

No estoy seguro de que esta sea la causa, pero también puede intentar jugar con el método html_safe. ERB podría estar escapando de su JSON porque cree que no es seguro para html. Trate de llamar a este método cuando se utiliza la cadena:

@object.to_json.html_safe 
+19

Cuidado: llamar html_safe sin escapar puede conducir a una vulnerabilidad XSS si' reincorporando el resultado en una etiqueta de script. – John

+0

Compruebe esto [railscast] (http://railscasts.com/episodes/204-xss-protection-in-rails-3) para ver cómo usar 'html_safe' con seguridad – Subtletree

+0

gracias! Esto es útil para mí. – rainstop3

1

Para volver json tienes que escribir tu render en el controlador de la siguiente manera:

render :json => @object 

y la .to_json se llamará automáticamente.

Si usted quiere incluir algunas relaciones, se puede hacer lo siguiente:

render :json => @post.to_json(:include => [:comments, :authors]) 

No estoy seguro de si funcionaría para utilizar un erb para hacer su JSON.

0

Puede invocar el renderizado en su controlador, pero eso será un problema si necesita representar más de unos pocos parciales para la posterior inserción del dom por parte del controlador. Necesitaba establecer múltiples fragmentos html en un hash, y pude devolver el erb que básicamente usa hash.to_json.html_safe como lo sugiere el neutrino más arriba y me permite representar múltiples parciales en el proceso.

31

El uso de html_escape o raw solo le dejará vulnerable to XSS.

el contrario, definen una versión sensible del ayudante json_escape (también conocido como j):

module ActionView::Base 
    def json_escape(s) 
    result = s.to_s.gsub('/', '\/') 
    s.html_safe? ? result.html_safe : result 
    end 

    alias j json_escape 
end 

utilizar de esta manera:

<script> 
    var Accounts = new Backbone.Collection; 
    Accounts.reset(<%=j @accounts.to_json.html_safe %>); 
    var Projects = new Backbone.Collection; 
    Projects.reset(<%=j @projects.to_json(:collaborators => true).html_safe %>); 
</script> 

Ver this post para más detalles.

Tenga en cuenta que hay un naming conflict entre j alias de json_escape en ERB :: Util y j alias de escape_javascript en ActionView :: Helpers :: JavaScriptHelper. Espero que el alias JavaScriptHelper se renombre a js.

+4

Esta respuesta debería ser la aceptada, es realmente sorprendente cuántas publicaciones en Internet sugieren usar html_safe sin escapar. – Ralf

+1

Creo que debería ser 'clase ActionView :: Base', no' módulo'. Además, ¿hay alguna razón para no hacerlo html_safe de manera predeterminada? No puedo pensar en ningún caso en el que quieras json_escape y luego html_escape. – Ralf

+0

Pregunta rápida: ¿dónde debería colocarse la definición del 'módulo ActionView :: Base ... end' en el proyecto de Rails? ¿Hay una ruta de acceso o archivo estándar para ello? –

0

Sólo se necesita to_json.html_safe:

> `'<script>'.to_json` 
=> "\"\\u003cscript\\u003e\"" 

parche para hacer que to_json responden a html_safe? y volver true automáticamente:

# just use .to_json instead of .to_json.html_safe 
ActiveSupport::JSON.class_eval do 
    class << self 
    def encode_with_html_safe *args 
     self.encode_without_html_safe(*args).html_safe 
    end 
    alias_method_chain :encode, :html_safe 
    end 
end