redirect_to nu funcționează așa cum era de așteptat în instrucțiunea if

Încerc să-mi dau seama de ce verificarea mea nul nu reușește atunci când apelez o metodă fără param sau un param id care nu produce înregistrări.

@game = Game.where(:id => params[:id]).first

if @game.nil?
  redirect_to root_path
end

În consolă funcționează bine.

>> pp @game.nil?
=> true

În aplicație, acest lucru eșuează (nu redirecționează niciodată!), de ce?

EDITARE 1:

În consolă (cu param id nul sau valoare de înregistrare inexistentă): Aceasta funcționează:

unless Game.exists?(params[:id])
  raise('ok')
end

Dar nu în aplicația din viața reală :( Am încercat aproape toate modalitățile de a verifica dacă înregistrarea este existentă sau validă, codul trece doar de această verificare și continuă așa cum este

EDITARE 2:

Privind un alt cod, am observat că am folosit o declarație de returnare, se pare că o rezolvă cu asta..

Lucrări:

unless Game.exists?(params[:id])
  redirect_to root_path
  return
end

Eșuează:

unless Game.exists?(params[:id])
  redirect_to root_path
end

Nu sunt sigur de ce are nevoie de o revenire după redirect_to explicit


person Rubytastic    schedule 07.10.2013    source sursă
comment
Nu vă pot spune de ce, dar o posibilă alternativă ar putea fi folosirea metodei de înregistrare activă exists?. Documentație găsită aici: apidock.com/rails/v3.2.13/ActiveRecord/ FinderMethods/exists%3F   -  person Paul Richter    schedule 07.10.2013
comment
Sunt pe șine 4, ar trebui să-mi actualizez postarea. Poate că acesta este motivul   -  person Rubytastic    schedule 07.10.2013
comment
Nu aveți nevoie de bitul == true. Aș folosi .exists? Pariez că tipul de returnare al extragerii nu este un obiect nil sau un obiect ActiveRecord.   -  person Adam Waite    schedule 07.10.2013
comment
Hmm, nu văd niciun motiv pentru care nu ar funcționa, indiferent de modul în care verificați existența înregistrării. Poate încercați să utilizați un depanator, cum ar fi pry și examinați ce se întâmplă în producție cod.   -  person Paul Richter    schedule 07.10.2013


Răspunsuri (2)


Dacă instrucțiunea redirect_to nu este ultima instrucțiune din controlerul tău, redirecționarea nu se va întâmpla niciodată.

if @game.nil?
  redirect_to root_path
  return
end

render @game

Fără întoarcere, redirect_to va fi înlocuit de un render. Trebuie să vedeți așa: Rails nu va redirecționa imediat după o instrucțiune redirect_to. Acesta va seta instrucțiunea undeva și odată ce controlerul dvs. revine, va prelua dacă există o acțiune setată de făcut, dacă nu, va trece la acțiunea implicită („vizualizarea acțiunii de redare”)

Posibil ar fi bine dacă ar exista un avertisment că vă suprascrieți acțiunea dacă aveți mai multe redirects/renders, dar în afară de asta, acesta este un comportament total bun.

Salutari.

EDITați

Pe o notă secundară, dacă utilizați Rails 4, utilizați Game.find_by(id: params[:id]) în loc de Game.where(id: params[:id]).first.
Dacă doriți pur și simplu să verificați existența, Game.exists?(params[:id]) este o modalitate bună, așa cum au menționat alții. Game.find(params[:id]) va genera o eroare dacă id nu poate fi găsit. Un indiciu bun ar fi să lucrați cu slug-uri, deoarece oamenii ar putea ghici ID-urile jocurilor dvs., ceea ce este practic o vulnerabilitate de securitate.

person Danyel    schedule 07.10.2013
comment
Hmm, nu am auzit niciodată de cerința ca redirect_to să fie ultima linie executată în metoda de acțiune. Am făcut un test rapid (șinele 4) și pare destul de acceptabil să-l plasezi destul de bine oriunde în corpul metodei de acțiune (deși foarte ciudat și s-ar putea să vezi un comportament ciudat dacă nu este în partea de jos). În cele din urmă, tot ceea ce face redirecționarea este să seteze locația și corpul răspunsului, pe care le puteți vedea aici în codul sursă. Am pierdut ceva? - person Paul Richter; 08.10.2013
comment
Nu știam sursa, dar acum e clar, da. Doar setează location, body și response. Nu face altceva! Deci, dacă suprascrieți aceste atribute, redirecționarea nu se va întâmpla niciodată, deoarece majoritatea browserelor urmează antetul Locație doar dacă codul de stare este 302. Oricum, nu există nicio magie în spatele acestuia. Dacă aveți un cod neclar în aplicația dvs. care ar putea suprascrie aceste atribute, redirecționarea dvs. ar putea eșua. - person Danyel; 09.10.2013

Continuă metoda de controler după această declarație if? redirect_to NU revine de la metodă. Dacă doriți să opriți execuția chiar acolo și să redirecționați, trebuie să reveniți în mod explicit făcând:

if @game.nil?
  redirect_to root_path && return
end
person Logan Serman    schedule 07.10.2013
comment
Mulțumesc. Tocmai mi-am dat seama că da :( M-am gândit că un redirect_to ar funcționa așa cum este, se pare că am mai multe locații în cod în care nu folosesc return, de aceea acesta este motivul pentru care eșuează - person Rubytastic; 07.10.2013
comment
Hmm, interesant. De ce redirecționarea nu ar proceda așa cum era de așteptat dacă fluxul programului a continuat dincolo de invocarea lui redirect_to? - person Paul Richter; 07.10.2013
comment
Pe o notă laterală.. o linie 1 eșuează.. așadar scrisă ca redirect_to root_path && return, cu excepția cazului în care Game.exists?(params[:id]. De ce nu ar funcționa așa cum era de așteptat dacă ați folosi acest one-liner? - person Rubytastic; 07.10.2013
comment
Nu sunt sigur de analizatorul Ruby în acest caz. Încercați să folosiți parantezele peste tot înainte de a le elimina: (redirect_to(root_path) && return) unless Game.exists?. - person Logan Serman; 07.10.2013