DEV Community

Colleen
Colleen

Posted on

1

Set a cookie read a cookie! How to (gently) collect user emails in a Rails application without Devise or requiring a password.

I was asked by a client to "soft-gate" user emails. The client wanted a list of emails from people using the application, but didn't want to discourage anyone from use. This presented a problem - how could I ask users' for their emails without preventing them from using the app (or pissing them off so much they closed the window)? And how could I remember they had visited and not ask for their email address again?

First things first - this solution is in no way even remotely secure. Devise has a "soft" sign up feature that allows users to start with entering only their email address (and then adding a password later) that you may want to check out if you're looking for real user authentication. In this case I was only trying to amass email addresses for a mailing list.

Question:

How to collect email addresses of users without being too annoying or preventing them from using the app?

Problem:

User state must be saved somehow, because you don't want the app requesting an email address every time the user visits the site.

Solution:

Save a cookie on the user's browser, and read the cookie to determine if the user has already visited the site. If they have, let them through. If they haven't, show a pop-up modal asking for their email address, but allow them to click anywhere on the page to close the modal and still use the site.

Step 1: Save a cookie

In the create method in the users controller add
cookies[:user_email] = @user.email if the user successfully saves.

Step 2: Create a modal

I'm lazy, this is almost directly from the bootstrap docs. My modal view renders my users#new form. I send in the locals as User.new because form_for user needs a user. Usually this is automagically done for you if the form is accessed via the create action.:

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <%= render partial: 'users/form', locals: { user: User.new } %>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
      </div> 
    </div>
  </div>
</div>

Step 3: Check for a cookie

So, the bootstrap modal is designed to be triggered by a button. This is straight from the docs. I want to trigger it ONLY if the cookie isn't set. This tripped me up at first, I tried accessing cookies[:user_email] in the view. No dice. The correct way:

In the root controller index (the homepage) I added this method:
(the index action of the root controller)

  def index
    @user_email = cookies[:user_email]
  end

Then in the view I checked for my cookie:
layouts/application.html.haml (or erb whatever you're into)

- if !@user_email
  #render-modal
  = render 'modals/user_email.html.erb'

So, @user_email is set in the index method. If @user_email does not exist (i.e. the cookie has not been created), I create a div with an id of render-modal.

Step 4: Show the modal

Quick jquery snippet to show the modal if the div created above exists:
app/assets/javascripts/modals.js

$(document).ready(function() {
  if ($('#render-modal').length) {
    $('#myModal').modal({show:true});
  }
});

There you have it! A quick way to render a pop-up modal if the user hasn't visited your site before. Now start collecting email addresses and sending great content to your users!

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay