2010-03-05 9 views

Antwort

22

Als Matchu geschrieben, Sie Punkt zwei von this post implementieren könnte (gleiche Verbindung er geschrieben, fand aber über meine als auch googeln). Dies fügt eine Abhängigkeit von JavaScript hinzu, die etwas sein kann oder auch nicht.

Alternativ können Sie in Fragment Caching aussehen. Auf diese Weise können Sie bestimmen Teile eine Seite cachen, aber immer noch die dynamischen Bereiche (wie Formulare mit Echtheits Token) erzeugen. Mit dieser Technik können Sie den Rest der Seite zwischenspeichern, aber für jede Anfrage ein neues Formular generieren.

Eine letzte (aber die ungünstigste) Lösung besteht darin, das Authentifizierungs-Token für diese bestimmte Aktion zu deaktivieren. Sie können dies tun, indem Sie die folgenden zu Beginn des Controllers fügte hinzu, dass Form zu erzeugen:

protect_from_forgery :except => [:your_action] 

Sie auch, indem Sie die folgenden zu Beginn protect_from_forgery für die gesamte Steuerung ausschalten:

skip_before_filter :verify_authenticity_token 
+0

danke für Ihre Antwort! – jacob

1

Es scheint nicht ein gut gelöst Problem. Point two on this blog post beschreibt, wie die Aufgabe mithilfe von jQuery ausgeführt wird, die jedoch eine JavaScript-Abhängigkeit einführt. Wiegen Sie Ihre Möglichkeiten, nehme ich an.

1

Sie könnten ein benutzerdefiniertes Tag im zwischengespeicherten Markup darstellen und es durch das bei jeder Anfrage gerenderte Formular ersetzen.

module CacheHelper 
    # Our FORM is deeply nested in the CACHED_PARTIAl, which we 
    # cache. It must be rendered on every request because of its 
    # authenticity_token by protect_from_forgery. Instead of splitting up the 
    # cache in multiple fragments, we replace a special tag with the custom 
    # form. 
    def cache_with_bla_form(resource, &block) 
    form = nil 
    doc = Nokogiri::HTML::DocumentFragment.parse(capture { cache("your_cache_key",&block) }) 
    doc.css('uncachable_form').each do |element| 
     form ||= render(:partial => 'uncachable_form', :resource => resource) 
     element.replace form 
    end 
    doc.to_html 
    end 
end 

Und Ihrer Meinung nach, die Sie gerade einen leeren uncachable_form Tag machen.

<%- cache_with_bla_form resource do %> 
    # cachable stuff.. 
    <uncachable_form /> 
    # more cachable stuff 
<%- end %> 

Ja, kann dies als ein Hack in Betracht gezogen werden, aber es wird nicht Fälschungsschutz lösen, braucht keine JS, und verringern Sie die Performance-Gewinn von Caching nur ein bisschen. Ich denke, jemand hat ein ähnliches Muster wie eine Rack Middleware implementiert.

module CacheHelper 
    def cache_with_updated_csrf(*a, &block) 
    Nokogiri::HTML::DocumentFragment.parse(capture { cache(*a,&block) }).tap do |doc| 
     doc.css("input[name=#{request_forgery_protection_token}]").each { |e| e['value'] = form_authenticity_token } 
    end.to_html.html_safe 
    end 
end 

Und = cache_with_updated_csrf do statt - cache do in Ihre Ansichten verwenden:

0

Als allgemeinere Lösung, können Sie auch alle zwischengespeicherten authenticity_tokens mit den aktuellen ersetzen. Kudos zu Bernard Potocki für die Idee.

1

Ich folgte der allgemeinen Lösung von Niklas Hofer, aber ich fand, dass seine Implementierung nicht mit der genauen Semantik des Rails-Cache-Helfers übereinstimmte. Es wurde nämlich versucht, den zwischengespeicherten HTML-Code aus dem Hilfsprogramm zurückzugeben, anstatt ihn mit safe_concat in den Puffer zu schreiben, was der Rails-Helfer tut.

Die Rails Helfer Nutzung ist wie folgt:

- cache do 
    = something 

Während seine Lösung dieser Syntax erforderlich:

= cache_with_updated_csrf do 
    = something 

Aus Gründen der Einheitlichkeit Ich würde es vorziehen, dass diese auf die gleiche Weise arbeiten. Daher habe ich diese Syntax verwendet:

- cache_form do 
    = something 

Hier ist meine Implementierung. Es wird auch das Zwischenspeichern überspringen, wenn das Zwischenspeichern deaktiviert ist, wie es der Rails-Helfer tut.

module CacheHelper 
    # Cache a form with a fresh CSRF 
    def cache_form(name = {}, options = nil, &block) 
    if controller.perform_caching 
     fragment = fragment_for(name, options, &block) 

     fragment_with_fresh_csrf = Nokogiri::HTML::DocumentFragment.parse(fragment).tap do |doc| 
     doc.css("input[name=#{request_forgery_protection_token}]").each { |e| e['value'] = form_authenticity_token } 
     end.to_html 

     safe_concat fragment_with_fresh_csrf 
    else 
     yield 
    end 

    nil 
    end 
end