Skip to content

How to Implement a Cookie Bar in Ruby on Rails

ALT

David Morales

Cookies
Photo by Markus Winkler on Unsplash

Selling a service or products online in the European Union obliges you to comply with the European cookie law. It consists of displaying a message to the user to know that the website uses cookies to track him. Because let’s be honest, is there any online shop out there not monitoring users? Analytics are crucial to see which product or page is the most viewed, or when and where visitors come from.

The European Union thinks this would violate the user’s privacy, so pages doing this should warn the user clearly. And the most popular solution is displaying a bar at the bottom or the top of the page.

Until you have the user’s consent, you cannot store cookies in the browser. Thus, if the user doesn’t accept, the visit will not be counted. This is highly problematic for most sites, so many do not follow this rule and just display the message.

I’m going to show you how to implement a straightforward example, using Ruby on Rails, of a cookie bar that will only install the Google Analytics cookie if the user gives consent by clicking the OK button.

Do you want to see this article in video format?

Sample Rails application

Let’s create a new Rails application step by step.

rails new eu-cookie-sampleCode language: Shell Session (shell)

Add the faker gem to your Gemfile:

gem 'faker'Code language: Ruby (ruby)

And rebuild Bundler dependencies:

cd eu-cookie-sample/
bundle installCode language: Shell Session (shell)

Now create a Home controller with an index view:

rails generate controller Home indexCode language: Shell Session (shell)

This will also create a new route for you. Replace it with a root route:

# config/routes.rb

root 'home#index'Code language: Ruby (ruby)

The final step to get your sample app ready is to display some random content. Delete all default content in app/views/home/index.html.erb and add this:

<% Faker::Lorem.paragraphs(number: 40).each do |paragraph| %>
  <p><%= paragraph %></p>
<% end %>Code language: ERB (Embedded Ruby) (erb)

Start the Rails server:

rails sCode language: Shell Session (shell)

And load localhost:3000 in your browser.

Your sample application is now showing a significant page enough to scroll.

Loading the cookies library

To handle cookies in the user’s browser, you are going to use the js-cookie JavaScript library. You can find it here: https://github.com/js-cookie/js-cookie

You are going to use its CDN version to load it. Just add this before the closing head tag in app/views/layouts/application.html.erb:

<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>Code language: HTML, XML (xml)

Building the message bar

Create a partial to build the message bar in app/views/layouts/_cookies_bar.html.erb:

<div id="cookies-bar" class="cookies-bar">
  <p>
    We use cookies. Do you accept them?
  </p>

  <%= link_to 'Accept', request.original_url, class: 'btn accept' %>
  <%= link_to 'Reject', request.original_url, class: 'btn reject' %>
</div>Code language: ERB (Embedded Ruby) (erb)

For simplicity, I have put a very simple text in the bar, but in reality it would be necessary to add a link pointing to some legal text and instructions to delete cookies.

Now include it in the application layout located at app/views/layouts/application.html.erb, just below the yield call:

<% if cookies[:allow_cookies].blank? %>
  <%= render 'layouts/cookies_bar' %>
<% end %>Code language: ERB (Embedded Ruby) (erb)

What you are checking here is whether the cookie named allow_cookies is set. If it is not, the bar is displayed.

Alternatively, you could also display this partial only for the production environment this way:

<% if !cookies[:allow_cookies] && Rails.env.production? %>Code language: ERB (Embedded Ruby) (erb)

Great! Refresh, and you will notice your bar at the very bottom of the page. But it is not sticky and looks messy. Let’s apply some styles.

Styling the bar

Rename the app/assets/stylesheets/home.scss to main.scss and paste this SCSS code:

body {
  font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}

.cookies-bar {
  position: sticky;
  bottom: 0;

  padding: 0px 10px 5px 10px;

  border: 1px solid #9CA3AF;
  border-bottom: none;
  background-color: #F3F4F6;

  .btn {
    display: block;
    border: 1px solid #4B5563;
    background-color: #6B7280;
    color: #FFF;
    padding: 5px;
    margin-bottom: 5px;
    text-align: center;
    text-decoration: none;

    &.accept:hover {
      background-color: #047857;
    }
    &.reject:hover {
      background-color: #B91C1C;
    }
  }

  @media (min-width: 768px) {
    display: flex;
    max-width: 700px;
    align-items: center;
    margin: 0 auto;
    padding-bottom: 0;

    .btn {
      padding: 10px 20px;
      margin-left: 10px;
    }
  }
}Code language: SCSS (scss)

This is how the bar looks on mobile:

Cookies bar on mobile

And this is the desktop version:

Cookies bar on desktop

The JavaScript code

Create the file app/javascript/custom/main.js (create the custom directory too) and paste this:

class CookieBar {
  constructor() {
    this.cookiesBar = document.getElementById('cookies-bar');
  }

  init() {
    if (this.cookiesAllowed()) {
      this.appendGACode();
    }

    this.addButtonBehaviors();
  }

  cookiesAllowed() {
    return Cookies.get('allow_cookies') === 'yes';
  }

  addButtonBehaviors() {
    if (!this.cookiesBar) {
      return;
    }

    this.cookiesBar.querySelector('.accept').addEventListener('click', () => this.allowCookies(true));

    this.cookiesBar.querySelector('.reject').addEventListener('click', () => this.allowCookies(false));
  }

  appendGACode() {
    const ga = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){" +
      "(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o)," +
      "m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)" +
      "})(window,document,'script','//www.google-analytics.com/analytics.js','ga');" +
      "ga('create', 'UA-XXXXX-Y', 'auto');" + "ga('send', 'pageview');";

    document.getElementsByTagName('head')[0].append('<script>' + ga + '</script>');
  }

  allowCookies(allow) {
    if (allow) {
      Cookies.set('allow_cookies', 'yes', {
        expires: 365
      });

      this.appendGACode();
    } else {
      Cookies.set('allow_cookies', 'no', {
        expires: 365
      });
    }

    this.cookiesBar.classList.add('hidden');
  }
}

window.onload = function() {
  const cookieBar = new CookieBar();

  cookieBar.init();
}
Code language: JavaScript (javascript)

This code has two parts: the class and the onload event.

If you look at the onload event, you will see that the class is created, and then the init method is called. Let’s break down the flow of these operations.

The file you just created has to be loaded by Rails. This is done by modifying the application.js file inside the packs subdirectory.

Add this require after the last import:

require("custom/main")Code language: Ruby (ruby)

Now try it!

If you are using Chrome or any other Chromium-based browser, open the developer tools and open the Application tab. There look for Cookies in the sidebar and expand it to click on the URL that appears. You will be able to see the cookie, its value, and you will be able to delete it.

I have uploaded the sample application to GitHub: https://github.com/davidmles/eu-cookie-sample

Conclusion

It’s not that hard to implement your solution to follow the EU cookies law. This way, you will control it better instead of using a plugin that limits you in some way.

I hope this law changes soon, so this is unnecessary, but meanwhile I think it’s a clean and straightforward solution.

Video version

Written by

David Morales

Computer Engineer

Teaching my software engineering knowledge in a creative way.

Would you like to get the 10 Ninja Keys of the Developer?

An exclusive PDF for Newsletter subscribers.

You will also be notified of future articles and affordable courses (in the pipeline) that will turn you into a ninja developer.

View privacy information

Comments (11)

Leave a reply

Please fill in all fields.

Your email address will not be published.

View privacy information