2010-09-21 5 views
30

Non ho problemi a effettuare chiamate AJAX tipiche da e verso Rails (3) con oggetti JSON e jQuery-rails (libreria jQuery più un file rails.js speciale).Gestione di JSON in template JS/ERB in Rails 3

In un controller, tuttavia, desidero RESTITUIRE alcuni JSON in un modello erb (create.js.erb) dopo una chiamata AJAX.

Ho provato ogni combinazione di cose nel controller (@ object.to_json, '[{"content": "ciao mondo"}]', ecc.) E nel modello stesso (JSON.parse() , citazioni singole, doppie citazioni, ecc), ma l'oggetto continua a rendere in questo modo:

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

e, di conseguenza, il mio codice jQuery non può analizzarlo e ottengo errori.

Come è necessario preparare il mio oggetto nel controller e quale sintassi erb ho bisogno nella vista per renderla come un oggetto JSON valido?

Grazie mille!

risposta

51

Non sono sicuro che questa sia la causa, ma puoi anche provare a giocare con il metodo html_safe. ERB potrebbe sfuggire al tuo JSON perché pensa che non sia sicuro per HTML. Prova a chiamare quel metodo quando si utilizza la stringa:

@object.to_json.html_safe 
+19

Attenzione: chiamando html_safe senza sfuggire può portare a una vulnerabilità XSS se' reinserire il risultato in un tag script. – John

+0

Controlla questo [railscast] (http://railscasts.com/episodes/204-xss-protection-in-rails-3) per vedere come usare 'html_safe' in modo sicuro – Subtletree

+0

grazie! Questo è utile per me. – rainstop3

1

Per tornare json dovete scrivere il vostro il rendering nel controller come segue:

render :json => @object 

e la .to_json verrà automaticamente chiamato.

Se si vuole includere alcuni rapporti, si potrebbe fare la seguente:

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

Non sono sicuro se avrebbe funzionato di utilizzare un erb per rendere il vostro JSON.

0

È possibile chiamare il rendering nel controller, ma questo sarà un problema se è necessario eseguire il rendering di più di alcuni partial per l'inserimento dom successivo da parte del gestore. Avevo bisogno di impostare più frammenti html in un hash, e sono stato in grado di restituire erb che fondamentalmente usa hash.to_json.html_safe come suggerito dal neutrino sopra e mi permette di rendere più partial durante il processo.

31

Utilizzare html_escape o raw da solo vi lascerà vulnerable to XSS.

Invece, definire una versione sensibile del helper json_escape (pseudonimo 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 

usare in questo modo:

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

Vedi this post per ulteriori dettagli.

essere consapevoli del fatto che c'è un naming conflict tra j alias per json_escape in ERB :: Util e j alias per escape_javascript in ActionView :: Helpers :: JavaScriptHelper. Spero che l'alias JavaScriptHelper venga rinominato in js.

+4

Questa risposta dovrebbe essere accettata: è davvero sconvolgente il modo in cui molti post su internet suggeriscono di usare html_safe senza fuggire. – Ralf

+1

Credo che dovrebbe essere 'class ActionView :: Base', non' module'. Inoltre, c'è qualche ragione per non renderlo html_safe di default? Non riesco a pensare a nessun caso in cui tu voglia json_escape e poi html_escape. – Ralf

+0

Domanda veloce: dove dovrebbe essere collocata la definizione del modulo ActionView :: Base ... end' nel progetto Rails? C'è un percorso o un file standard per questo? –

0

Solo è necessario to_json.html_safe:

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

Patch per rendere to_json rispondere alle html_safe? e tornare true automaticamente:

# 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