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
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...
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.
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.
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.
|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.
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.
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!
# 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
# 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|