Rails going backwards
Tags: rails
Published: 2021-09-20 11:22:26

---
title: Rails going backwards
published: true
description: How do you go back in Rails?
tags: rails
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxo4k4jmdih80mp0jhy4.png
---

## Introduction

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.

## Solutions
1. [Solution 1: Back with hardcoding](#solution-1-hardcoding the path)
2. [Solution 2: Back with referer](#solution-2-back-with-referer)
3. [Solution 3: Back with JavaScript](#solution-3-back-with-javascript)
4. [Solution 4: Back with session](#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](https://api.rubyonrails.org/v6.1.4/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to). An example is in listing 1.

#### Listing 1
```erb
<%= link_to "my link', :back %>
```

[link_to :back rails code](https://github.com/rails/rails/blob/main/actionview/lib/action_view/helpers/url_helper.rb#L39) It is described in the docs as:  

> Using a :back Symbol instead of an options hash will generate a link to the referer (a JavaScript back link will be used in place of a referer if none exists).

What's a referer? MDN give a [definition for referer](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/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](https://en.wikipedia.org/wiki/HTTP_referer#Etymology), 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](https://stackoverflow.com/questions/6880659/in-what-cases-will-http-referer-be-empty).

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

![What is the referer?](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/isitut94oliucwplifyl.png)

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 `Show` to `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.

![Back using referer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gn9gw7pw79iag67cozg.png)

#### b. POST

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 3: Back with JavaScript

Another popular class of answers are [JavaScript](https://stackoverflow.com/a/46609048/1511504). JavaScript is also used in [Rails `:back` if the referer can't be found.](https://github.com/rails/rails/blob/main/actionview/lib/action_view/helpers/url_helper.rb#L48) Example of Back with Javascript is in listing 2.

#### Listing 2
```erb
 <%= link_to 'Back', 'javascript:history.back()' %>
```

JavaScript back uses the browser's page stack. Each time it visits a page, it is added to a stack of URLs. Going back meant popping each page reference off the stack. [Here's a Stackoverflow on how a Browser back button works](https://stackoverflow.com/a/1313941/1511504). The downside for this, if the user had gone to the edit and then saved and returned to the show page and _then_ started to use back you would have to go "back" via the edit which might not be what the user expected.

![Back using JavaScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4y98ycfui169tzdcm82q.png)

## Solution 4: Back with session

The final class of solutions were [saving the routes in the session](https://stackoverflow.com/a/16213741/1511504). 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

```ruby
# 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

```ruby
# app/controllers/my_controller.rb
class MyController < ApplicationController
  ...
  def index
    ...
    # this could have been in a before_action
    store_last_index_page
    ...
  end
end
```
#### View code

```erb
# 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 %>
```

## Summary

There are four ways to go backwards:

| # | link_to                 | Type     | Description      |
|:---|:-----------------------|:---------|:-----------------|
| 1 | link_to my_path | Hardcoded| Clean, limited to one route  |
| 2 | link_to :back   | Referer  | Clean, limited to one hop |
| 3 | link_to 'javascript:history.back()' | JavaScript | Access to Browser back |
| 4 | link_to get_session_variable() | Session | Powerful but complicated |

### References

[link_to Rails docs (6.1.4)](https://api.rubyonrails.org/v6.1.4/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to)
[url_helper Rails code (6.1.4)] (https://github.com/rails/rails/blob/main/actionview/lib/action_view/helpers/url_helper.rb#L39)
[MDN - Referer](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer)
[HTTP_referer#Etymology](https://en.wikipedia.org/wiki/HTTP_referer#Etymology)
[In what cases will the Referer be empty?](https://stackoverflow.com/questions/6880659/in-what-cases-will-http-referer-be-empty)
[How does the Back button in a web browser work?](https://stackoverflow.com/a/1313941/1511504)