2010-01-26 21 views
160

Ho una pagina che elenca tutti i progetti con intestazioni e paginazione ordinabili.Come reindirizzare alla pagina precedente in Ruby On Rails?

path: 
/projects?order=asc&page=3&sort=code 

ho scelto di modificare uno dei progetti

path: 
projects/436/edit 

Quando clicco salvare in quella pagina, si chiama il metodo progetti di controllo/aggiornamento. Dopo aver aggiornato il codice, desidero reindirizzare al percorso in cui ero prima di fare clic su modifica di un progetto specifico. In altre parole, voglio essere sulla stessa pagina con lo stesso ordinamento.

Ho visto link_to (: back) e ho pensato che: back potrebbe funzionare in redirect_to (: back), ma questo è un no go.

puts YAML::dump(:back) 
yields the following: 
:back 

Tutte le idee su Come potrei farlo funzionare. Sembra un problema che potrebbe essere risolto facilmente, ma sono nuovo di RoR.

risposta

289

Nella vostra azione di modifica, memorizzare l'url richiedente l'hash della sessione, che è disponibile attraverso più richieste:

session[:return_to] ||= request.referer 

quindi reindirizzare ad esso nella vostra azione di aggiornamento, dopo un salvataggio corretto:

redirect_to session.delete(:return_to) 
+0

Questo ha fatto il trucco. Grazie! – easement

+65

Suggerisco 'redirect_to session.delete (: return_to)' nell'azione di aggiornamento. Questo ripulisce il valore dalla sessione, poiché non è più necessario. – stigi

+15

non ha più schede aperte confondere questa logica? – jones

33

Questo è come lo facciamo nella nostra applicazione

def store_location 
    session[:return_to] = request.fullpath if request.get? and controller_name != "user_sessions" and controller_name != "sessions" 
end 

def redirect_back_or_default(default) 
    redirect_to(session[:return_to] || default) 
end 

in questo modo è solo archiviare l'ultima richiesta GET nel parametro della sessione :return_to, quindi tutti i moduli, anche se il POST di più istanze funzionerebbe con :return_to.

+3

'request.request_uri' non è più disponibile, quindi suggerisco di usare' request.fullpath' invece – anka

+0

@anka Aggiornato. Grazie per il commento – MBO

+2

sì, è abbastanza buono. Suggerirei generalmente di non usare le istruzioni 'e' e' or' in 'if'. Usa '&&' e '||' invece. Dettagli [qui] (http://devblog.avdi.org/2010/08/02/using-and-and-or-in-ruby/). – Achilles

46

mi piace il metodo di Jaime con una sola eccezione, ha funzionato meglio per me di ri-memorizzare il referer ogni volta:

def edit 
    session[:return_to] = request.referer 
... 

La ragione è che se si modificano più oggetti, sarete sempre reindirizzato alla il primo URL che hai archiviato nella sessione con il metodo di Jaime. Ad esempio, supponiamo di avere oggetti Apple e Orange. Correggo Apple e session[:return_to] viene impostato sul riferimento di tale azione. Quando vado a modificare Arance usando lo stesso codice, session[:return_to] non verrà impostato perché è già definito. Così, quando aggiorno Orange, verrò inviato al referente della precedente azione di modifica di # Apple.

+0

sì, ma puoi suggerire cosa fare se per caso lo stesso URL è stato archiviato come sei? Sei alla mela e sei venuto dalla mela. E tu vuoi che la precedente posizione – Uko

88

Perché il redirect_to(:back) non funziona per te, perché è un no?

redirect_to(:back) funziona come un incantesimo per me. E 'solo una scorciatoia per redirect_to(request.env['HTTP_REFERER'])

http://apidock.com/rails/ActionController/Base/redirect_to (Rails pre 3) o http://apidock.com/rails/ActionController/Redirecting/redirect_to (Rails 3)

prega di notare che si sta redirect_to(:back) deprecato in Rails 5.È possibile utilizzare

redirect_back(fallback_location: 'something') invece (vedi http://blog.bigbinary.com/2016/02/29/rails-5-improves-redirect_to_back-with-redirect-back.html)

+11

'redirect_to: back' non funzioni bene per me, dici di visitare'/posts/new', questo è impostato come referer per la prossima richiesta, quindi dopo che il modulo è stato inviato correttamente mostra formare di nuovo, cioè '/ posts/new'. Funziona comunque bene per altri scopi. – Kris

+0

Cioè, OP vuole reindirizzare indietro due volte. Scommetto che potrebbe semplicemente "redirect_to projects_path". –

+0

Sì. redirect_back non funziona altrettanto bene in Rails 5 – strizzwald

18

request.referer è impostato per rack ed è impostato come segue:

def referer 
    @env['HTTP_REFERER'] || '/' 
end 

Basta fare una redirect_to request.referer e sarà sempre reindirizzare alla vera pagina di riferimento, o il root_path ('/'). Questo è essenziale quando si passa i test che falliscono nei casi di navigatore diretto a una pagina particolare in cui il controller getta un redirect_to: torna

+0

Non è sicuro quale file stavi guardando ma all'origine del rack, questo è il modo in cui il termine "referer" è stato definito il [28 Mar 2011] (https://github.com/rack/rack/blob/828e2ab0396c5bbf4b5ccd76e6392a475633a81f/lib/rack /request.rb#L222-L224), ed è così che viene definito come [oggi] (https://github.com/rack/rack/blob/bbae0ce30ddeb9f8a2a208d08e479ee5a85a1a02/lib/rack/request.rb#L289-L291). Cioè, '|| '/' 'non fa parte della definizione. –

11

In rotaie 5, secondo le istruzioni in Rails Guide, si può usare:

redirect_back(fallback_location: root_path) 

La posizione 'indietro' viene estratta dall'intestazione HTTP_REFERER che non è garantita per essere impostata dal browser. Ecco perché dovresti fornire un 'fallback_location'.

+0

Questa funzione appare nei binari 5. – Chambeur

+0

@Chambeur, sì sì. L'ho corretto grazie! – pSkarl

+0

@pSkarl Come posso passare un oggetto 'notice' con l'istruzione' redirect_back' per dire all'utente che qualcosa è andato storto con un messaggio flash? –

1

Per coloro che sono interessati, ecco la mia implementazione estendendo la risposta originale di MBO (scritta contro i binari 4.2.4, ruby ​​2.1.5).

class ApplicationController < ActionController::Base 
    after_filter :set_return_to_location 

    REDIRECT_CONTROLLER_BLACKLIST = %w(
    sessions 
    user_sessions 
    ... 
    etc. 
) 

    ... 

    def set_return_to_location 
    return unless request.get? 
    return unless request.format.html? 
    return unless %w(show index edit).include?(params[:action]) 
    return if REDIRECT_CONTROLLER_BLACKLIST.include?(controller_name) 
    session[:return_to] = request.fullpath 
    end 

    def redirect_back_or_default(default_path = root_path) 
    redirect_to(
     session[:return_to].present? && session[:return_to] != request.fullpath ? 
     session[:return_to] : default_path 
    ) 
    end 
end 
Problemi correlati