จะเปลี่ยนเส้นทางไปยังหน้าก่อนหน้าใน 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)ในการดำเนินการอัปเดต สิ่งนี้จะล้างค่าจากเซสชันเนื่องจากไม่จำเป็นต้องใช้อีกต่อไป
stigi

19
ไม่ได้เปิดหลายแท็บให้สับสนด้วยเหตุผลนี้
โจน

12
คุณทำไม่ได้redirect_to request.refererเหรอ
Elle Mundy

1
@DanMundy ไม่เพื่อให้สามารถใช้งานได้request.referer.refererหากเป็นไปได้ @ Jaime Bellmyer ทำไม||=ล่ะ
x-yuri

@ โจนส์ใช่ นอกจากนี้ยังมีความสับสนหากคุณเปลี่ยนเป็นการแก้ไขแบบอื่น ฉันสนใจด้วยเช่นกันทำไม || =
เมาโร

99

ทำไมมันredirect_to(:back)ไม่ได้ผลสำหรับคุณ

redirect_to(:back)ทำงานเหมือนจับใจสำหรับฉัน มันเป็นทางลัดสำหรับ redirect_to(request.env['HTTP_REFERER'])

http://apidock.com/rails/ActionController/Base/redirect_to (pre 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 "ไม่ทำงานได้ดี" หมายถึงอะไร รายละเอียดใด ๆ
Pascal

@pascalbetz สิ่งที่ฉันหมายถึงคือถ้าHTTP_REFERERไม่ได้ตั้งไว้คุณอาจจะได้รับActionController::RedirectBackErrorคุณจะต้องช่วยเหลือจากข้อยกเว้นนี้ในกรณีนั้น จากความเข้าใจของฉันใช้redirect_backไม่จำเป็นต้องมีการจัดการข้อยกเว้นใด ๆ fallback_locationตั้งแต่คุณถูกบังคับให้ให้ บางที 'ทำงานไม่ดี' อาจไม่ใช่วิธีที่ถูกต้อง
strizzwald

45

ฉันชอบวิธีการของ Jaime โดยมีข้อยกเว้นประการหนึ่งมันทำงานได้ดีกว่าสำหรับฉันในการจัดเก็บผู้อ้างอิงทุกครั้ง:

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

เหตุผลก็คือถ้าคุณแก้ไขวัตถุหลายรายการคุณจะถูกเปลี่ยนเส้นทางกลับไปที่ URL แรกที่คุณเก็บไว้ในเซสชันด้วยวิธีของ Jaime ตัวอย่างเช่นสมมติว่าฉันมีวัตถุของ Apple และ Orange ฉันแก้ไข Apple และsession[:return_to]ตั้งค่าให้เป็นผู้อ้างอิงของการกระทำนั้น เมื่อฉันไปแก้ไขส้มโดยใช้รหัสเดียวกันsession[:return_to]จะไม่ได้รับการตั้งค่าเพราะมันถูกกำหนดไว้แล้ว ดังนั้นเมื่อฉันอัปเดตออเรนจ์ฉันจะถูกส่งไปยังผู้อ้างอิงของการดำเนินการแก้ไข # Apple ก่อนหน้า


ใช่ แต่คุณสามารถแนะนำสิ่งที่ต้องทำถ้าเก็บ 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
yup ที่ค่อนข้างดี ฉันอยากจะแนะนำโดยทั่วไปไม่ได้ใช้andและorในifงบ ใช้&&และ||แทน รายละเอียดที่นี่
Achilles

19

ใน Rails 5 ตามคำแนะนำใน Rails Guide คุณสามารถใช้:

redirect_back(fallback_location: root_path)

ตำแหน่ง 'ย้อนกลับ' จะถูกดึงจากส่วนหัว 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

เพียงทำredirect_to request.refererและมันจะเปลี่ยนเส้นทางไปยังหน้าอ้างอิงจริงหรือ root_path ('/') สิ่งนี้เป็นสิ่งสำคัญเมื่อผ่านการทดสอบที่ล้มเหลวในกรณีของการนำทางโดยตรงไปยังหน้าใดหน้าหนึ่งซึ่งตัวควบคุมโยนการเปลี่ยนเส้นทางไปที่: กลับ


ไม่แน่ใจว่าไฟล์ที่คุณกำลังหาที่ แต่ที่มาชั้นนี้เป็นวิธีที่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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.