Как перенаправить на предыдущую страницу в Ruby On Rails?


186

У меня есть страница, на которой перечислены все проекты с сортируемыми заголовками и нумерацией страниц.

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

Я выбираю для редактирования один из проектов

path:
projects/436/edit

Когда я нажимаю сохранить на этой странице, он вызывает метод контроллера / обновления проекта. После того, как я обновлю код, я хочу перенаправить на путь, по которому я был, прежде чем я щелкнул редактировать конкретный проект. Другими словами, я хочу быть на той же странице с той же сортировкой.

Я видел link_to (: back) и думал, что: back может работать в redirect_to (: back), но это не пойдет.

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

Любые идеи о том, как я мог бы заставить это работать. Это похоже на проблему, которую легко решить, но я новичок в RoR.

Ответы:


323

В действии редактирования сохраните запрашивающий URL в хеше сеанса, который доступен для нескольких запросов:

session[:return_to] ||= request.referer

Затем перенаправьте на него в действии обновления после успешного сохранения:

redirect_to session.delete(:return_to)

68
Я бы предложил redirect_to session.delete(:return_to)в действии обновления. Это очищает значение от сеанса, так как оно больше не нужно.
— Стиги

19
не несколько открытых вкладок не путают эту логику?
— Джонс

12
Не могли бы вы просто redirect_to request.referer?
— Эль Манди,

1
@ DanMundy Нет, чтобы это работало, это должно быть request.referer.referer, если это возможно. @ Хайме Беллмайер Почему ||=?
— x-yuri

@ Джонс да. Существует также путаница, если вы переключаетесь на другую модель редактирования. Мне также интересно, почему || =
— Mauro

99

Почему у вас redirect_to(:back)не работает, почему нет?

redirect_to(:back)работает как шарм для меня. Это просто короткий путь для redirect_to(request.env['HTTP_REFERER'])

http://apidock.com/rails/ActionController/Base/redirect_to (до Rails 3) или http://apidock.com/rails/ActionController/Redirecting/redirect_to (Rails 3)

Обратите внимание, что redirect_to(:back)это устарело в Rails 5. Вы можете использовать

redirect_back(fallback_location: 'something')вместо этого (см. http://blog.bigbinary.com/2016/02/29/rails-5-improves-redirect_to_back-with-redirect-back.html )


12
redirect_to :backне работает хорошо для меня тоже, говорят , вы посещаете /posts/new, это устанавливается в качестве реферера для следующего запроса, поэтому после того , как форма успешно отправлена она показывает форму снова, то есть /posts/new. Однако он хорошо работает для других целей.
— Крис

То есть OP хочет перенаправить назад дважды. Могу поспорить, он мог просто redirect_to projects_path.
— x-yuri

Да. redirect_back не работает так же хорошо в Rails 5
— strizzwald

@strizzwald, что значит "плохо работает"? Какие-нибудь детали?
— Паскаль

@pascalbetz, я имел в виду, что если HTTP_REFERERне установлено, вы можете получить ActionController::RedirectBackError, вам придется спасаться от этого исключения в этом случае. Насколько я понимаю, использование redirect_backне требует обработки исключений, так как вы вынуждены предоставлять fallback_location. Может быть, «не работает хорошо» - это неправильный способ выразить это.
— Strizzwald

45

Мне нравится метод Хайме с одним исключением, для меня лучше работать каждый раз, когда я заново сохраняю реферер:

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

Причина в том, что если вы редактируете несколько объектов, вы всегда будете перенаправлены обратно на первый URL, который вы сохранили в сеансе с помощью метода Jaime. Например, допустим, у меня есть объекты Apple и Orange. Я редактирую Apple и получаю session[:return_to]разрешение от этого действия. Когда я иду, чтобы редактировать апельсины, используя тот же код, session[:return_to]не будет установлен, потому что он уже определен. Поэтому, когда я обновлю Orange, меня отправят рефереру предыдущего действия Apple # edit.


да, но можете ли вы предложить, что делать, если случайно был сохранен тот же URL-адрес, что и у вас? Вы в яблоке, и вы пришли из яблока. И вы хотите предыдущее местоположение
— Uko

33

Вот как мы делаем это в нашем приложении

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

Таким образом, вы сохраняете только последний GET-запрос в параметре :return_toсеанса, поэтому все формы, даже если многократно POSTed будет работать :return_to.


3
request.request_uriбольше недоступен, поэтому я предлагаю использовать request.fullpathвместо этого
— анка

@anka Обновлено. Спасибо за комментарий
— MBO

2
да это довольно хорошо. Я бы только предложил вообще не использовать andи orв ifвысказываниях. Используйте &&и ||вместо. Подробности здесь .
— Ахиллес

19

В рельсах 5, согласно инструкциям в Rails Guides, вы можете использовать:

redirect_back(fallback_location: root_path)

Местоположение 'back' берется из заголовка HTTP_REFERER, который не гарантируется браузером. Вот почему вы должны предоставить 'fallback_location'.


Эта функция появляется в рельсах 5.
— Chambeur

@pSkarl Как я могу передать noticeобъект с redirect_backоператором, чтобы сказать пользователю, что что-то пошло не так с флэш-сообщением?
— alexventuraio

2
Ну, я мог бы решить эту проблему, выполнив: redirect_back(fallback_location: root_path, notice: "Something went wrong!"). Надеюсь, это может как-то помочь.
— alexventuraio

18

request.referer устанавливается Rack и устанавливается следующим образом:

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

Просто сделайте a, redirect_to request.refererи он всегда будет перенаправлен на истинную ссылающуюся страницу, или root_path ('/'). Это важно при прохождении тестов, которые терпят неудачу в случаях прямой навигации к определенной странице, на которой контроллер выдает redirect_to: back


Не уверен, какой файл вы смотрели, но у источника стойки, вот как referer было определено по состоянию на 28 марта 2011 года , и это то, как он определен на сегодняшний день . То есть || '/'не является частью определения.
— Мачек

1

Для тех, кто заинтересован, вот моя реализация, расширяющая оригинальный ответ MBO (написанный против 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.