This is a Rails review on how to link back to the page you've just visited from. I had struggled to get a solution, and reading through Stackoverflow I don't think I'm alone in this. This is my take and I hope it is useful or can become useful with the help of others.
- Solution 1: Back with hardcoding
- Solution 2: Back with referer
- Solution 4: Back with session
Solution 1: Back with hardcoding
If there's only one route in and out of the page. Hardcoding the path out is a clean option. From here, it gets more interesting...
Solution 2: Back with referer
A popular back solution is to use Rails
:back symbol to be passed to link_to. An example is in listing 1.
<%= link_to "my link', :back %>
link_to :back rails code It is described in the docs as:
What's a referer? MDN give a definition for referer they say:
The Referer HTTP request header contains an absolute or partial address of the page making the request. When following a link, this would be the address of the page containing the link.
So, requests often have a URL of the page you were last on. This is the referer, spelt referer in official documents, and Rails uses it to get back again. However, the referer can be missing if the user typed the URL into the search bar directly, as well as other exceptions.
Checking for the referer
I wanted to see how it works. First, I found a way to get the referer in Firefox. You can check the referer by going to the Firefox inspector and then the network tab and searching for referer. In this example, we have navigated to edit page and checking for referer, which is the show page (FYI: the resource was feedbacks).
There are two issues with using the referer:
a. Back twice - if you go back more than once, the referer will point to where you were last. Not where you were when you were last on that page!
b. POST - if you perform a
POST on the page, the referer is also reset.
a. Back Twice
We can see, in table 1, that back is fine for step 1 but on step 2 going back ends up in a loop between
Edit. In other words, the Referer only remembers one hop and can quickly form a loop because it is always pointing to where you were on the last hop.
Table 1: Stepping through an application, and what happens if you go back?
|Step||Page||Referer||Back||Back again||And again||And again|
|0||Home||Empty||→ Empty||→ Empty||→ Empty||→ Empty|
|1||Show||Home||→ Home||→ Empty||→ Empty||→ Empty|
|2||Edit||Show||→ Show||→ Edit||⇾ Show||→ Edit*|
- It will keep looping between show and edit.
Another way to express this information is in a diagram where we can see the black lines as user clicks and blue lines when the user back clicks.
It did not work when you are
POST a form on the page and then want to go back. If I had to,
POST on the show page, say I added a comment and stayed on the
Show page. After you
POST the referer gets set to the
show page, the current page, and back will take you to the
show page. In other words, nowhere.
Back with referer summary
link_to :back is only useful when you want to go back one page. In our case, once it had reached edit, it won't remember the original route it got to show. Further, when you
POST on the page, the referer can get reset to the current page and losing the route back.
Solution 4: Back with session
The final class of solutions were saving the routes in the session. To get this to work, I added methods to the
ApplicationController to set and retrieve the values, as well as code to update the session in the controller and use the session variable in the view's link_to - Listing 3 contains the code.
This is not nearly as nice as the other two solutions, much less cohesion, as there's already 3 files required compared to 1 liners for the other solutions.
I'm not saying this is good code, I'm just saying this is what I had to do to get it to work!
Listing 3 Example of using session to go backwards
# app/controllers/application_controller.rb class ApplicationController ... helper_method :retrieve_last_index_page_or_default ... def store_last_index_page session[:last_index_page] = request.fullpath end def retrieve_last_index_page_or_default(default_path: root_path) session[:last_index_page] || default_path end ... end
Updating session in controller code
# app/controllers/my_controller.rb class MyController < ApplicationController ... def index ... # this could have been in a before_action store_last_index_page ... end end
# app/views/my/index.html.erb # this could have been a variable set in controller <%= link_to retrieve_last_index_page_or_default do %> ... <% end %>
There are four ways to go backwards:
|1||link_to my_path||Hardcoded||Clean, limited to one route|
|2||link_to :back||Referer||Clean, limited to one hop|
|4||link_to get_session_variable()||Session||Powerful but complicated|
link_to Rails docs (6.1.4)
url_helper Rails code (6.1.4)
MDN - Referer
In what cases will the Referer be empty?
How does the Back button in a web browser work?
Top comments (3)
This was very helpful. I have a project with complex (to me at least) navigation where I can end up in one place from several different paths and I always want to "back up" along those same paths. I found that your "session" solution was exactly what I needed in those cases. Thanks very much.
Thanks! I was frustrated about why
:backis getting me into a loooooooooop. Ended up just doing the
When you hit the loop you think "I really don't know what I'm doing do I?". Glad to know I helped as I'm always reading and watching your output.