DEV Community


Posted on

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.


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


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


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] = 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 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>
      <div class="modal-body">
        <%= render partial: 'users/form', locals: { user: } %>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>

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]

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

- if !@user_email
  = 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:

$(document).ready(function() {
  if ($('#render-modal').length) {

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!

Top comments (0)