Jak przekierować do poprzedniej strony w Ruby On Rails?

186

Mam stronę z listą wszystkich projektów z sortowalnymi nagłówkami i stronicowaniem.

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

Wybieram edycję jednego z projektów

path:
projects/436/edit

Po kliknięciu opcji Zapisz na tej stronie wywołuje metodę kontrolera / aktualizacji projektów. Po zaktualizowaniu kodu chcę przekierować do ścieżki, na której byłem, zanim kliknąłem edytować konkretny projekt. Innymi słowy, chcę być na tej samej stronie z tym samym sortowaniem.

Widziałem link_to (: back) i pomyślałem, że: back może działać w redirect_to (: back), ale to nie jest wyjście.

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

Wszelkie pomysły na to, w jaki sposób mogę to uruchomić. Wygląda na to, że problem można łatwo rozwiązać, ale jestem nowy w RoR.

serwitut
źródło

Odpowiedzi:

323

W akcji edycyjnej zapisz żądający adres URL w skrócie sesji, który jest dostępny dla wielu żądań:

session[:return_to] ||= request.referer

Następnie przekieruj do niego w akcji aktualizacji po udanym zapisie:

redirect_to session.delete(:return_to)
Jaime Bellmyer
źródło
68
Sugerowałbym redirect_to session.delete(:return_to)w akcji aktualizacji. Czyści to wartość z sesji, ponieważ nie jest już potrzebna.
stigi,
19
czy otwarcie kilku kart nie myli tej logiki?
Jones
12
Nie mogłeś po prostu redirect_to request.referer?
Elle Mundy
1
@ DanMundy Nie, żeby zadziałało, powinno być request.referer.referer, jeśli to możliwe. @Jaime Bellmyer Dlaczego ||=?
x-yuri
@jones tak. Istnieje również zamieszanie, jeśli przejdziesz do edycji innego modelu. Interesuje mnie również, dlaczego || =
Mauro
99

Dlaczego redirect_to(:back)dla ciebie nie działa, dlaczego nie można go przejść?

redirect_to(:back)działa jak urok dla mnie. To tylko skrót do redirect_to(request.env['HTTP_REFERER'])

http://apidock.com/rails/ActionController/Base/redirect_to (wcześniej Rails 3) lub http://apidock.com/rails/ActionController/Redirecting/redirect_to (Rails 3)

Pamiętaj, że redirect_to(:back)jest on przestarzały w Rails 5. Możesz użyć

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

Pascal
źródło
12
redirect_to :backteż nie działa dla mnie dobrze, powiedzmy, że odwiedzasz /posts/new, jest to ustawione jako odsyłacz do następnego żądania, więc po pomyślnym przesłaniu formularza pokazuje formularz ponownie, tj /posts/new. Działa jednak dobrze do innych celów.
Kris,
Oznacza to, że OP chce przekierować dwa razy z powrotem. Założę się, że mógł redirect_to projects_path.
x-yuri
Tak. redirect_back nie działa również w Railsach 5
strizzwald,
@strizzwald co znaczy „nie działa dobrze”? Jakieś szczegóły?
Pascal
@pascalbetz, co miałem na myśli to, że jeśli HTTP_REFERERnie jest ustawiony, możesz dostać ActionController::RedirectBackError, będziesz musiał uratować od tego wyjątku w takim przypadku. Z mojego zrozumienia, używanie redirect_backnie wymaga obsługi wyjątków, ponieważ jesteś zmuszony to zapewnić fallback_location. Może „nie działa dobrze” nie jest właściwym sposobem na wyrażenie tego.
strizzwald
45

Podoba mi się metoda Jaime'a z jednym wyjątkiem. Lepiej działało dla mnie ponowne przechowywanie odsyłacza za każdym razem:

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

Powodem jest to, że jeśli edytujesz wiele obiektów, zawsze zostaniesz przekierowany z powrotem do pierwszego adresu URL zapisanego w sesji metodą Jaime. Załóżmy na przykład, że mam obiekty Apple i Orange. Ja edytuję Apple i session[:return_to]ustawiam na osobę polecającą tę akcję. Kiedy przejdę do edycji pomarańczy przy użyciu tego samego kodu, session[:return_to]nie zostanie ustawiony, ponieważ jest już zdefiniowany. Więc kiedy zaktualizuję Orange, zostanę wysłany do strony odsyłającej z poprzedniej akcji edycji # Apple.

Tony
źródło
tak, ale czy możesz zasugerować, co zrobić, jeśli przypadkowo zapisano ten sam adres URL, co obecnie? Jesteś przy jabłku i pochodzisz z jabłka. I chcesz poprzednią lokalizację
Uko
33

Tak to robimy w naszej aplikacji

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

W ten sposób przechowujesz tylko ostatnie żądanie GET w :return_toparametrze sesji, więc wszystkie formularze, nawet jeśli wielokrotne testowanie POST działałoby :return_to.

MBO
źródło
3
request.request_urinie jest już dostępny, więc sugeruję użyć request.fullpathzamiast tego
anka
@anka Zaktualizowano. Dzięki za komentarz
MBO
2
tak, to całkiem nieźle. Proponuję tylko ogólnie nie używać andi orw ifsprawozdaniu. Użyj &&i ||zamiast. Szczegóły tutaj .
Achilles
19

W szynach 5, zgodnie z instrukcjami w Przewodnikach po szynach, możesz użyć:

redirect_back(fallback_location: root_path)

Lokalizacja „wstecz” jest pobierana z nagłówka HTTP_REFERER, co nie jest gwarantowane przez przeglądarkę. Właśnie dlatego powinieneś podać „fallback_location”.

pSkarl
źródło
Ta funkcja pojawia się w szynach 5.
Chambeur
@pSkarl Jak mogę przekazać noticeobiekt z redirect_backinstrukcją, aby poinformować użytkownika, że ​​coś poszło nie tak z komunikatem flash?
alexventuraio,
2
Cóż, mogę rozwiązać ten problem, wykonując: redirect_back(fallback_location: root_path, notice: "Something went wrong!"). Mam nadzieję, że to może jakoś pomóc.
alexventuraio,
18

request.referer jest ustawiony przez Rack i jest ustawiony następująco:

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

Po prostu zrób a, redirect_to request.referera zawsze przekieruje na prawdziwą stronę odsyłającą lub ścieżkę root_path ('/'). Jest to niezbędne przy zdawaniu testów, które kończą się niepowodzeniem w przypadku bezpośredniego przejścia do konkretnej strony, na której kontroler rzuca przekierowanie_do: wstecz

Steve Tipton
źródło
Nie jestem pewien, który plik był oglądany, ale u źródła w szafie, oto jak refererzostało zdefiniowane na 28 marca 2011 r. I tak jest zdefiniowane na dzień dzisiejszy . Oznacza to, że || '/'nie jest częścią definicji.
maček
1

Dla tych, którzy są zainteresowani, oto moja implementacja rozszerzająca oryginalną odpowiedź MBO (napisaną przeciwko szynom 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
aschyiel
źródło