DEV Community

Cécile Rougnaux
Cécile Rougnaux

Posted on • Originally published at cecilerx.github.io on

Customize Devise’s flash messages

PROBLEM: I don’t like the “Welcome, you have signed up successfully” flash message that Devise displays when a user signs up. I want something more personalized, I want a warm welcome. Easy! In a blink, it will be done! Well, not that fast, actually.

a road to somewhere

What do I need to display a personalized message?

To add a bit of warmness to this boring process of signing up, I want to address the new user by her/his username. So first I need to modify my user model by adding a username attribute.



$ rails generate migration AddUsernameToUsers username:string



Enter fullscreen mode Exit fullscreen mode

Then to save the change of my DB schema:



$ rails db:migrate



Enter fullscreen mode Exit fullscreen mode

Now I have to give my user the possibility to set a nice username. As far as I can see, the Devise’s default views have only 2 required fields for signing up: email and password. Ok, so I need to access the registrations views to modify it.

Where are the Devise registrations Views?

In my app folder, Devise views are nowhere to be found. Obviously they are hidden, but there must be a way to see them!Here comes the great documentation written by the authors of the gem1. Devise provides a simple generator to copy all the views associated with authentication in a dedicated folder.



$ rails generate devise:views



Enter fullscreen mode Exit fullscreen mode

Now I have a Devise folder, and inside I can find a registration folder with the new.html.erb file I expected.I just need to add the username field on the form:



 <div class="form-inputs">
        <%= f.input :username,
                    required: true,
                    autofocus: true,
                    input_html: { autocomplete: "username" }%>
        <%= f.input :email,
                    required: true,
                    autofocus: true,
                    input_html: { autocomplete: "email" }%>
        <%= f.input :password,
                    required: true,
                    hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length),
                    input_html: { autocomplete: "new-password" } %>
        <%= f.input :password_confirmation,
                    required: true,
                    input_html: { autocomplete: "new-password" } %>
      </div>



Enter fullscreen mode Exit fullscreen mode

Where is the controller responsible for registration actions?

When a user provides a correct email, password and username, a new user is registered. Under the hood, the Registrations Controller is hit, and specifically its create method that holds the logic for registration. If the process is successful, the controller will ask the associated view to display a welcome message.I need to access this controller to modify the create method in the way I want. Right, but by default, Devise controllers are hidden as well. Not a problem, there is also a simple generator to create customizable controllers :



$ rails generate devise:controllers users



Enter fullscreen mode Exit fullscreen mode

I specify the users as the scope, in order to keep the Devise controllers separated from the others. The controllers associated with authentication will be in a users folder, inside the controllers folder of my app.

How do I modify the Registrations Controller?

Now I can see my Registrations Controller, but not in the way I had imagined.



  # POST /resource
  # def create
  # super
  # end



Enter fullscreen mode Exit fullscreen mode

I know The ‘super’ keyword2 has something to do with parent/child classes. I could keep it and add a new behavior, but as I want to modify and not add, I will simply replace it by a custom code.Well, I don’t want to customize all of it, so I would prefer to keep the original code and modify what I need. A quick look to the Devise’s source of the Registrations Controller code 3 and here it goes:



# POST /resource

def create
  build_resource(sign_up_params)
  resource.save

  yield resource if block_given?
  if resource.persisted?
    if resource.active_for_authentication?
    set_flash_message! :notice, :signed_up
    sign_up(resource_name, resource)
    respond_with resource, location: after_sign_up_path_for(resource)
    else
    set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
    expire_data_after_sign_in!
    respond_with resource, location: after_inactive_sign_up_path_for(resource)
    end
  else
  clean_up_passwords resource
  set_minimum_password_length
  respond_with resource
  end
end



Enter fullscreen mode Exit fullscreen mode

I have 2 possibilities here, depends if I plan to internationalize my app in the future.If not, I could simply replace the



set_flash_message! :notice, :signed_up



Enter fullscreen mode Exit fullscreen mode

by



flash[:notice] = "Hello there, #{resource.username}! Glad to welcome you here!"



Enter fullscreen mode Exit fullscreen mode

But I do want to use I18n gem soon, so I prefer to pass the username variable to the set_flash_message method and then modify the devise.en.yml file that holds all the english translations of the flash messages.



set_flash_message! :notice, :signed_up, :username => resource.username



Enter fullscreen mode Exit fullscreen mode

How do I customize the flash message?

Now that the set_flash_message method can access the username variable, I just need to open the devise.en.yml file, find the registration sign_up message and modify it:



en:
  devise:
    registrations:
      sign_up: "Hello there, %{username}! Glad to welcome you here!"



Enter fullscreen mode Exit fullscreen mode

Debugging…

Everything seems fine, I restarted the server, and now I am ready to receive my nice welcome message.A quick test and well, how disappointing! I have the new flash message, yes, but I don’t see my username appear. What can be wrong I ask? It was supposed to be super fast, and I already spent too much time understanding the whole thing.Checking the rails console I realize that the last registered user has a username set to NIL. I entered a beautiful one though, but Devise refused to save it in my DB. Must be a security problem I guess, for sure Devise methods have strong parameters. Just need to find where to add the username parameter to the list.

Devise strong parameters

Once again Devise documentation is my friend. I discover that I don’t need to modify Devise source code, but I have to configure the permitted parameters in the Application Controller in 2 steps.

  • Adding a before action


class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?



Enter fullscreen mode Exit fullscreen mode
  • Adding a configure_permitted_parameters method


protected

def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end

Enter fullscreen mode Exit fullscreen mode




And now, the magic happens ;)

screenshot of the welcome flash message

All references for Devise are from their great documentation. For example, to configure the views, see: https://github.com/heartcombo/devise#configuring-views

For a quick overview about the ‘super’ keyword in ruby, see: https://medium.com/rubycademy/the-super-keyword-a75b67f46f05

Devise’s source code is open source and available in the heartcombo github repository. For example, the Registration Controller’s source code is here: https://github.com/heartcombo/devise/blob/master/app/controllers/devise/registrations_controller.rb

Top comments (1)

Collapse
 
sowenjub profile image
Arnaud Joubay

I think I would override set_flash_message! instead.