Як перенаправити на попередню сторінку в Ruby On Rails?


186

У мене є сторінка, на якій перераховані всі проекти, які мають впорядковані заголовки та сторінки.

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

Я вирішу редагувати один із проектів

path:
projects/436/edit

Коли я натискаю кнопку "Зберегти" на цій сторінці, він викликає контролер проектів / метод оновлення. Після оновлення коду я хочу переспрямувати шлях, на якому я був, перш ніж натиснути, щоб редагувати конкретний проект. Іншими словами, я хочу бути на одній сторінці з тим же сортуванням.

Я побачив link_to (: назад) і подумав, що: back може працювати в redirect_to (: назад), але це не йде.

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?
Elle Mundy

1
@DanMundy Ні, для роботи це повинно бути request.referer.referer, якщо це можливо. @Jaime Bellmyer Чому ||=?
x-yuri

@jones так. Існує також плутанина, якщо ви переходите до редагування іншої моделі. Мене також цікавить, чому || =
Мауро

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. Однак це добре працює для інших цілей.
Кріс

Тобто ОП хоче переспрямувати назад двічі. Б'юсь об заклад, що він міг просто 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]не буде встановлено, оскільки він уже визначений. Тож коли я оновлюю помаранчевий, я надішлюсь до реферера попередньої дії 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

@anka Оновлено. Дякую за коментар
MBO

2
Так, це дуже добре. Я б тільки запропонував, як правило, не використовувати andі orу ifвисловлюваннях. Використовуйте &&і ||замість цього. Деталі тут .
Ахілл

19

У рейках 5, згідно з інструкціями в Посібниках по рейках, ви можете використовувати:

redirect_back(fallback_location: root_path)

Місце "назад" виводиться із заголовка HTTP_REFERER, який браузер не гарантує встановлення. Ось чому ви повинні надати "резервне_значення".


Ця функція з’являється в рейках 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: назад


Не впевнений, який файл ви шукали, але джерело стійки, саме так refererбуло визначено станом на 28 березня 2011 року , і саме так воно визначається станом на сьогодні . Тобто, || '/'не є частиною визначення.
maček

1

Для тих, хто цікавиться, ось моя реалізація, яка розширює оригінальну відповідь MBO (написана проти рейок 4.2.4, рубін 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.