2010-09-21 4 views
30

Ich habe keine Probleme mit typischen AJAX-Aufrufe von und nach Rails (3) mit JSON-Objekten und jQuery-Rails (jQuery-Bibliothek plus eine spezielle rails.js-Datei).Behandlung von JSON in JS/ERB-Vorlage in Rails 3

In einem Controller möchte ich jedoch einige JSON in einem Erb-Template (create.js.erb) nach einem AJAX-Aufruf zurückgeben.

Ich habe jede Kombination von Dingen im Controller versucht (@ object.to_json, '[{"content": "Hallo Welt"}]' usw.) und in der Vorlage selbst (JSON.parse() , einfache Anführungszeichen, doppelte Anführungszeichen, etc.), aber das Objekt hält weiter so machen:

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

und als Ergebnis, mein jQuery-Code nicht analysieren kann und ich Fehler bekommen.

Wie muss ich mein Objekt im Controller vorbereiten, und welche Erb-Syntax brauche ich in der Ansicht, damit es als gültiges JSON-Objekt gerendert wird?

Vielen Dank!

Antwort

51

Ich bin mir nicht sicher, dass dies der Grund ist, aber Sie können auch versuchen, mit html_safe Methode herumspielen. ERB könnte Ihrem JSON entkommen, weil es denkt, dass es nicht html-sicher ist. Versuchen Sie diese Methode aufrufen, wenn die Zeichenfolge mit:

@object.to_json.html_safe 
+19

Vorsicht: Aufruf html_safe ohne Flucht in eine XSS-Schwachstelle führen kann, wenn Sie‘ Wiedereinbetten des Ergebnisses in ein Skript-Tag. – John

+0

Überprüfen Sie diese [Railscast] (http://railscasts.com/episodes/204-xss-protection-in-rails-3), um zu sehen, wie man 'html_safe' sicher verwendet – Subtletree

+0

Danke! Das ist hilfreich für mich. – rainstop3

1

json zurückzukehren Sie schreiben müssen, um Ihre in der Steuerung wie folgt angezeigt:

render :json => @object 

und die .to_json automatisch aufgerufen wird.

Wenn Sie einige Beziehungen einschließen würde wollen, können Sie folgendes tun:

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

Ich bin nicht sicher, ob es eine erb verwenden würde arbeiten, um Ihre json zu machen.

0

Sie können Render in Ihrem Controller aufrufen, aber das wird ein Problem sein, wenn Sie möglicherweise mehr als ein paar Partials für nachfolgende dom Insertion durch den Handler rendern müssen. Ich musste mehrere HTML-Fragmente in einen Hash setzen, und ich konnte Erb zurückgeben, der im Grunde genommen hash.to_json.html_safe verwendet, wie es Neutrino oben vorgeschlagen hat, und mir erlaubt, mehrere Teiltöne in diesem Prozess zu rendern.

31

Mit html_escape oder raw allein lassen Sie vulnerable to XSS.

Stattdessen eine vernünftige Version der json_escape (auch bekannt als j) Helfer definieren:

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 

es wie folgt verwendet:

<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> 

this post für weitere Details.

bewusst sein, dass ein naming conflict zwischen j-json_escape in ERB :: Util aliased es gibt und j-escape_javascript in ActionView aliased :: Helpers :: JavaScriptHelper. Ich hoffe, dass der JavaScriptHelper-Alias ​​in js umbenannt wird.

+4

Diese Antwort sollte die akzeptierte sein - es ist wirklich schockierend, wie viele Beiträge im Internet vorschlagen, html_safe zu verwenden, ohne zu entkommen. – Ralf

+1

Ich glaube, es sollte "Klasse ActionView :: Base" sein, nicht "Modul". Gibt es auch einen Grund, es nicht standardmäßig html_safe zu machen? Ich kann mir keinen Fall vorstellen, in dem du json_escape und dann html_escape willst. – Ralf

+0

Schnelle Frage: Wo sollte die 'Modul ActionView :: Base ... end'-Definition im Rails-Projekt platziert werden? Gibt es einen Standardpfad oder eine Datei dafür? –

0

Nur to_json.html_safe benötigt:

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

Patch-to_json reagieren auf html_safe? zu machen und zurück true automatisch:

# 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