¿Cómo redirigir a la página anterior en Ruby On Rails?

186

Tengo una página que enumera todos los proyectos que tienen encabezados y paginación ordenables.

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

Elijo editar uno de los proyectos

path:
projects/436/edit

Cuando hago clic en guardar en esa página, llama al controlador de proyectos / método de actualización. Después de actualizar el código, quiero redirigir a la ruta en la que estaba antes de hacer clic en editar un proyecto específico. En otras palabras, quiero estar en la misma página con la misma clasificación.

Vi link_to (: back) y pensé que: back podría funcionar en redirect_to (: back), pero eso no es posible.

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

Alguna idea sobre cómo podría hacer que esto funcione. Parece un problema que se resolvería fácilmente, pero soy nuevo en RoR.

comodidad
fuente

Respuestas:

323

En su acción de edición, almacene la url solicitante en el hash de sesión, que está disponible en varias solicitudes:

session[:return_to] ||= request.referer

Luego, redirígelo en tu acción de actualización, después de un guardado exitoso:

redirect_to session.delete(:return_to)
Jaime Bellmyer
fuente
68
Sugeriría redirect_to session.delete(:return_to)en la acción de actualización. Esto limpia el valor de la sesión, ya que ya no es necesario.
stigi
19
¿No tiene varias pestañas abiertas confundir esta lógica?
jones
12
¿No podrías simplemente redirect_to request.referer?
Elle Mundy
1
@DanMundy No, para que funcione debería serlo request.referer.referer, si eso fuera posible. @Jaime Bellmyer ¿Por qué ||=?
x-yuri
@ Jones sí. También hay confusión si cambia a otra edición de modelo. También estoy interesado en por qué || =
Mauro
99

¿Por qué redirect_to(:back)no funciona para ti, por qué es un no ir?

redirect_to(:back)Funciona como un encanto para mí. Es solo un atajo para redirect_to(request.env['HTTP_REFERER'])

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

Tenga en cuenta que redirect_to(:back)está en desuso en Rails 5. Puede usar

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

Pascal
fuente
12
redirect_to :backtampoco funciona bien para mí, digamos que visita /posts/new, esto se establece como el referente para la próxima solicitud, por lo que después de que el formulario se envíe con éxito, muestra el formulario nuevamente, es decir /posts/new. Sin embargo, funciona bien para otros fines.
Kris
Es decir, OP quiere redirigir de nuevo dos veces. Apuesto a que podría simplemente redirect_to projects_path.
x-yuri
Si. redirect_back no funciona tan bien en Rails 5
strizzwald
@strizzwald ¿qué significa "no funciona bien"? Cualquier detalle?
Pascal
@pascalbetz, lo que quise decir es que si HTTP_REFERERno está configurado, es posible ActionController::RedirectBackErrorque tenga que rescatarlo de esta excepción en ese caso. Según tengo entendido, el uso redirect_backno requiere ningún manejo de excepciones, ya que está obligado a proporcionar fallback_location. Tal vez "no funciona bien" no es la forma correcta de decirlo.
Strizzwald
45

Me gusta el método de Jaime con una excepción, funcionó mejor para mí volver a almacenar el árbitro cada vez:

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

La razón es que si edita varios objetos, siempre será redirigido a la primera URL que almacenó en la sesión con el método de Jaime. Por ejemplo, digamos que tengo objetos Apple y Orange. Edito Apple y me pongo session[:return_to]al árbitro de esa acción. Cuando vaya a editar Naranjas con el mismo código, session[:return_to]no se configurará porque ya está definido. Entonces, cuando actualice el Orange, me enviarán al árbitro de la acción de edición Apple # anterior.

Tony
fuente
sí, pero ¿puede sugerir qué hacer si accidentalmente se almacenó la misma URL que usted? Estás en Apple y vienes de Apple. Y quieres ubicación anterior
Uko
33

Así es como lo hacemos en nuestra aplicación

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

De esta manera, solo almacena la última solicitud GET en el :return_toparámetro de sesión, por lo que todos los formularios, incluso cuando la POSTed en varias ocasiones funcionaría :return_to.

MBO
fuente
3
request.request_uriya no está disponible, así que sugiero usar request.fullpathen su lugar
anka
@anka Actualizado. Gracias por tu comentario
MBO
2
Sí, eso es bastante bueno. Por lo general, solo sugeriría no usar andy oren las ifdeclaraciones. Uso &&y en su ||lugar. Detalles aquí .
Achilles
19

En los rieles 5, según las instrucciones de las Guías de rieles, puede usar:

redirect_back(fallback_location: root_path)

La ubicación 'atrás' se extrae del encabezado HTTP_REFERER que no se garantiza que el navegador establezca. Es por eso que debe proporcionar una 'ubicación de retorno'.

pSkarl
fuente
Esta característica aparece en los rieles 5.
Chambeur
@pSkarl ¿Cómo puedo pasar un noticeobjeto con la redirect_backdeclaración para decirle al usuario que algo salió mal con un mensaje flash?
alexventuraio
2
Bueno, yo podría resolver este haciendo: redirect_back(fallback_location: root_path, notice: "Something went wrong!"). Espero que pueda ayudar de alguna manera.
alexventuraio
18

request.referer Rack lo establece y se establece de la siguiente manera:

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

Simplemente haga un redirect_to request.referery siempre redirigirá a la página de referencia verdadera, o al root_path ('/'). Esto es esencial cuando se pasan pruebas que fallan en casos de navegación directa a una página en particular en la cual el controlador lanza un redirect_to: back

Steve Tipton
fuente
No estoy seguro de qué archivo estaba mirando, pero en la fuente del rack, así es como refererse definió a partir del 28 de marzo de 2011 , y así es como se define a partir de hoy . Es decir, || '/'no es parte de la definición.
maček
1

Para aquellos que estén interesados, aquí está mi implementación que amplía la respuesta original de MBO (escrita contra rails 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
fuente