Comment rediriger vers la page précédente dans Ruby On Rails?

186

J'ai une page qui répertorie tous les projets qui ont des en-têtes et une pagination triables.

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

J'ai choisi d'éditer l'un des projets

path:
projects/436/edit

Lorsque je clique sur Enregistrer sur cette page, cela appelle la méthode contrôleur / mise à jour des projets. Après avoir mis à jour le code, je souhaite rediriger vers le chemin sur lequel j'étais avant de cliquer sur modifier un projet spécifique. En d'autres termes, je veux être sur la même page avec le même tri.

J'ai vu link_to (: back) et j'ai pensé que: back peut fonctionner dans redirect_to (: back), mais ce n'est pas possible.

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

Des idées sur la façon dont je pourrais faire fonctionner cela. Cela semble être un problème qui serait facilement résolu, mais je suis nouveau sur RoR.

servitude
la source

Réponses:

323

Dans votre action de modification, stockez l'URL de la demande dans le hachage de session, qui est disponible pour plusieurs demandes:

session[:return_to] ||= request.referer

Puis redirigez-vous vers celui-ci dans votre action de mise à jour, après une sauvegarde réussie:

redirect_to session.delete(:return_to)
Jaime Bellmyer
la source
68
Je suggérerais redirect_to session.delete(:return_to)dans l'action de mise à jour. Cela nettoie la valeur de la session, car elle n'est plus nécessaire.
stigi du
19
le fait d'avoir plusieurs onglets ouverts ne confond-il pas cette logique?
jones
12
Tu ne pourrais pas juste redirect_to request.referer?
Elle Mundy le
1
@DanMundy Non, pour que ça marche, ça devrait l'être request.referer.referer, si cela était possible. @Jaime Bellmyer Pourquoi ||=?
x-yuri
@jones oui. Il y a également confusion si vous passez à une autre modification de modèle. Je suis aussi intéressé par pourquoi || =
Mauro
99

Pourquoi ne redirect_to(:back)fonctionne pas pour vous, pourquoi est-ce interdit?

redirect_to(:back)fonctionne comme un charme pour moi. C'est juste un raccourci pour redirect_to(request.env['HTTP_REFERER'])

http://apidock.com/rails/ActionController/Base/redirect_to (avant Rails 3) ou http://apidock.com/rails/ActionController/Redirecting/redirect_to (Rails 3)

Veuillez noter que redirect_to(:back)c'est obsolète dans Rails 5. Vous pouvez utiliser

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

Pascal
la source
12
redirect_to :backne fonctionne pas bien pour moi non plus, disons que vous visitez /posts/new, cela est défini comme référent pour la prochaine demande, donc une fois le formulaire soumis avec succès, il affiche à nouveau le formulaire, c'est-à-dire /posts/new. Cela fonctionne cependant bien à d'autres fins.
Kris
Autrement dit, OP veut rediriger deux fois. Je parie qu'il pourrait juste redirect_to projects_path.
x-yuri
Ouais. redirect_back ne fonctionne pas aussi bien dans Rails 5
strizzwald
@strizzwald que signifie "ne fonctionne pas bien"? Des détails?
Pascal
@pascalbetz, ce que je voulais dire, c'est que si ce HTTP_REFERERn'est pas défini, vous pourriez obtenir ActionController::RedirectBackError, vous devrez vous sauver de cette exception dans ce cas. D'après ce que je comprends, l'utilisation redirect_backne nécessite aucune gestion des exceptions puisque vous êtes obligé de fournir fallback_location. Peut-être que «ne fonctionne pas bien» n'est pas la bonne façon de le dire.
strizzwald
45

J'aime la méthode de Jaime à une exception près, cela fonctionnait mieux pour moi de re-stocker le référent à chaque fois:

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

La raison en est que si vous modifiez plusieurs objets, vous serez toujours redirigé vers la première URL que vous avez stockée dans la session avec la méthode de Jaime. Par exemple, disons que j'ai des objets Apple et Orange. J'édite Apple et je suis session[:return_to]défini sur le référent de cette action. Lorsque je vais modifier les oranges en utilisant le même code, session[:return_to]ne sera pas défini car il est déjà défini. Ainsi, lorsque je mettrai à jour l'Orange, je serai envoyé au référent de la précédente action d'édition Apple #.

Tony
la source
oui, mais pouvez-vous suggérer quoi faire si accidentellement la même URL a été stockée que vous êtes? Vous êtes chez Apple et vous venez d'Apple. Et vous voulez l'emplacement précédent
Uko
33

Voici comment nous procédons dans notre application

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 cette façon, vous ne stockez que la dernière requête GET dans le :return_toparamètre de session, de sorte que tous les formulaires, même lorsque plusieurs fois POSTed fonctionneraient :return_to.

MBO
la source
3
request.request_urin'est plus disponible, donc je suggère d'utiliser à la request.fullpathplace
anka
@anka Mis à jour. Merci pour vos commentaires
MBO
2
ouais c'est plutôt bien. Je suggérerais seulement de ne pas utiliser généralement andet ordans les ifdéclarations. Utilisez &&et à la ||place. Détails ici .
Achilles
19

Dans les rails 5, conformément aux instructions des guides de rails, vous pouvez utiliser:

redirect_back(fallback_location: root_path)

L'emplacement «back» est extrait de l'en-tête HTTP_REFERER qui n'est pas garanti d'être défini par le navigateur. C'est pourquoi vous devriez fournir un 'fallback_location'.

pSkarl
la source
Cette fonction apparaît dans les rails 5.
Chambeur
@pSkarl Comment puis-je passer un noticeobjet avec l' redirect_backinstruction afin de dire à l'utilisateur que quelque chose s'est mal passé avec un message flash?
alexventuraio
2
Eh bien, je pouvais résoudre ce problème en faisant: redirect_back(fallback_location: root_path, notice: "Something went wrong!"). J'espère que cela pourrait aider d'une manière ou d'une autre.
alexventuraio
18

request.referer est défini par Rack et est défini comme suit:

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

Faites simplement un redirect_to request.refereret il sera toujours redirigé vers la vraie page de référence, ou le root_path ('/'). Ceci est essentiel lors de la réussite des tests qui échouent en cas de navigation directe vers une page particulière dans laquelle le contrôleur jette un redirect_to: back

Steve Tipton
la source
Je ne sais pas quel fichier vous regardiez mais à la source du rack, c'est ainsi que cela a refererété défini au 28 mars 2011 , et c'est ainsi qu'il est défini aujourd'hui . Autrement dit, || '/'ne fait pas partie de la définition.
maček
1

Pour ceux qui sont intéressés, voici mon implémentation étendant la réponse originale de MBO (écrite contre les 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
la source