2009-04-20 23 views
8

Nota Originariamente era una domanda relativa agli errori 404, ma ora è una questione sul perché la patch che ho applicato avrebbe fatto la differenza.Qual è la differenza tra [X, Y, Z] .each {| m | includi m} e includi X, Y, Z?

Come si ottiene un'azione memorizzata nella cache per restituire un 404 su tutte le richieste che generano un'eccezione ActiveRecord :: RecordNotFound, non solo la prima richiesta?

Ad esempio, se si avvia un progetto di rotaie vuote, aggiungere un modello di prodotto e un controller, configurare il database.yml, configurare il backend di cache in production.rb, rake db: migrare, quindi avviare in produzione e premere il sito per un oggetto inesistente, ad es http://localhost:3000/product/show/1234

class ProductController < ApplicationController 

    caches_action :show 

    def show 
    @product = Product.find(params[:id]) 
    render :text => "asdf" 
    end 

end 

La prima volta che la pagina viene colpito, si ritorna alla pagina 404 come previsto. Tuttavia, ogni colpo successivo a quell'URL restituisce una pagina vuota con 200 OK. Come si fa a restituire 404 ogni volta?

Qui ci sono le richieste CURL, seguito dal log

~ $ curl -I http://0.0.0.0:3000/product/show/1234 
HTTP/1.1 404 Not Found 
Connection: close 
Date: Mon, 20 Apr 2009 22:49:18 GMT 
Content-Type: text/html; charset=utf-8 
Cache-Control: no-cache 
Content-Length: 14097 

~ $ curl -I http://0.0.0.0:3000/product/show/1234 
HTTP/1.1 200 OK 
Connection: close 
Date: Mon, 20 Apr 2009 22:49:19 GMT 
X-Runtime: 6 
Content-Type: text/html; charset=utf-8 
Cache-Control: no-cache 
Content-Length: 0 

La seconda risposta è chiaramente sbagliata.

Ecco una copia del registro per i 2 richieste:

Processing ProductController#show (for 127.0.0.1 at 2009-04-20 17:35:24) [GET] 
    Parameters: {"id"=>"1234"} 

ActiveRecord::RecordNotFound (Couldn't find Product with ID=1234): 
    app/controllers/product_controller.rb:6:in `show' 

Rendering rescues/layout (not_found) 


Processing ProductController#show (for 127.0.0.1 at 2009-04-20 17:35:30) [GET] 
    Parameters: {"id"=>"1234"} 
Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x23e36d4 @options={:cache_path=>nil, :store_options=>{}, :layout=>nil}>] rendered_or_redirected. 
Filter chain halted as [#<ActionController::Filters::AroundFilter:0x23e3580 @kind=:filter, @options={:unless=>nil, :if=>nil, :only=>#<Set: {"show"}>}, @method=#<ActionController::Caching::Actions::ActionCacheFilter:0x23e36d4 @options={:cache_path=>nil, :store_options=>{}, :layout=>nil}>, @identifier=nil>] did_not_yield. 
Completed in 12ms (View: 0, DB: 0) | 200 OK [http://0.0.0.0/product/show/1234] 

In effetti, se si tira l'azione nella cache dalla cache, si ha una sorta di immondizia vuoto in là.

cache.fetch("views/0.0.0.0:3000/product/show/1234") 
=> ["", nil, [], []] 

Cosa sto facendo di sbagliato qui?

Modifica

ho confermato che Rails 2.1.2 e 2.2.2 non presentano questo comportamento, ma 2.3.2 fa. (cioè le versioni precedenti non memorizzano una risposta vuota nella cache e lanciano un 404 per le richieste successive)

Sto riscontrando problemi con i bordi Rails, perché il caricamento causa il seguente errore all'avvio del server: foobar/vendor/rails/ActiveSupport/lib/active_support/dependencies.rb: 440: in `load_missing_constant ': non inizializzata ActionController costante :: fail-safe (NameError)

ho testato contro l'attuale capo del 2 -3 ramo stabile, 375e8976e3, e anch'esso mostra questo comportamento.

Modifica # 2 ho cercato di rintracciare quando il cambiamento si è verificato nel codebase Rails per determinare se sia stato intenzionale. Sembra che this seemingly innocuous commit sia il punto in cui inizia il bug.

Ecco i dettagli della bisezione, dove 404 indica il comportamento desiderato, 200 è indesiderato.

 
2-3-stable branch 
    375e8976e3 - 200 
    b1c989f28d - 200 
    beca1f2e15 - 200 
    f1fff0a48 - 200 
    f1e20ce9a7 - 200 
    a5004573d8 - 200 
    2e1132fad8 - 200 - the difference seems to start at this commit 
    c69d8c043f - 404 
    d961592886 - 404 
    276ec16007 - 404 
    0efec6452 - 404 
    13c6c3cfc5 - 404 
    fb2325e35 - 404 

2-2 stable 
    3cb89257b4 - 404 

Ecco una patch che inverte il cambiamento, che, applicato al tag v2.3.2.1, cioè dc88847e5ce392eed210b97525c14fca55852867, risolve il problema. Io, tuttavia, non sono abbastanza intelligente da capire perché questo cambiamento apparentemente piccolo farebbe davvero la differenza! Forse qualcuno più intelligente di me potrebbe far luce sulla situazione?

diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb 
index 0facf70..0790807 100644 
--- a/actionpack/lib/action_controller/base.rb 
+++ b/actionpack/lib/action_controller/base.rb 
@@ -1403,12 +1403,9 @@ module ActionController #:nodoc: 
    end 

    Base.class_eval do 
- [ Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers, 
-  Cookies, Caching, Verification, Streaming, SessionManagement, 
-  HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, 
-  RecordIdentifier, RequestForgeryProtection, Translation 
- ].each do |mod| 
-  include mod 
- end 
+ include Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers 
+ include Cookies, Caching, Verification, Streaming, SessionManagement 
+ include HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods 
+ include RecordIdentifier, RequestForgeryProtection, Translation 
    end 
end 

Modifica # 3 La patch sembra risolvere anche il relativo bug, in mostra al di sopra, dove la "completata nel XYms (DB: Z) | 404 Not Found [http://0.0.0.0/product/1234]" non ha mostrato in il ceppo.

Modifica # 4 È possibile che questo cerotto interruppe l'altro in ActionPack, così ho approfondito e ha generato una correzione per il problema che non causa danni collaterali. La patch e gli aggiornamenti successivi saranno a the rails lighthouse

risposta

16

Sembra che include(X, Y, Z) funzioni effettivamente in un ordine diverso da include X; include Y; include Z.

Di seguito ho incollato il codice C che implementa il metodo # include in Ruby 1.8.6.

static VALUE 
rb_mod_include(argc, argv, module) 
    int argc; 
    VALUE *argv; 
    VALUE module; 
{ 
    int i; 

    for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE); 
    while (argc--) { 
     rb_funcall(argv[argc], rb_intern("append_features"), 1, module); 
     rb_funcall(argv[argc], rb_intern("included"), 1, module); 
    } 
    return module; 
} 

Anche se non hai familiarità con interni C di Ruby, è abbastanza chiaro che questa funzione ha un ciclo for iterare verso l'alto per verificare che il tipo di tutti gli argomenti è T_MODULE, e quindi utilizza un ciclo while iterazione verso il basso per includere effettivamente i moduli - quindi i moduli in include(X, Y, Z) verrebbero effettivamente inclusi nell'ordine Z, Y, X. Non ho esaminato tutti i moduli Rails in questione, ma immagino ci sia qualcosa che dipende dall'ordine che ha iniziato a fallire una volta che l'ordine di inclusione è stato cambiato.

+0

in effetti, sembra ragionevole. Grazie per la tua ricerca e intuizione! –

Problemi correlati