Adding Custom Fields to Devise
By: Lukasz Muzyka, On:
This tutorial assumes you have already completed:
Once you setup Devise, you may soon realize that you need to allow users to save more information about themselves. What about name, gender or date of birth? Sometimes we need a little more than just an email.
Step 1: Run Rails Generate Device
If you carefully explore app/views
in our application you will notice that there is no HTML templates for all the login, registration or password reminding forms. This is because all the forms are sitting inside Devise gem. If we want to edit the forms we need to ask Devise to export all templates to our views folder.
Inside the folder with your application, run this in your terminal:
bash
$ rails generate devise:views users
After we run this command, you will find a bunch of new folders under app/views/users.
These are the forms we will be using to register users, log them in, and reset passwords. We can try to edit one of the templates and see what happens.
app/views/users/registrations/new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %></div>
<div><%= f.label :password %>
<%= f.password_field :password, autocomplete: "off" %></div>
<div><%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off" %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "users/shared/links" %>
Step 2: Change and Save Headline
Let's change the header of the page "Sign up" to "Register"
app/views/users/registrations/new.html.erb
<h2>Register</h2>
Now, if you logout and try to register, you would expect to see the new title of the page "Register." However, you will still see "Sign up." This is because we need to adjust the configuration of Devise. Go to config/initializers/devise.rb
and look for the line:
config/initializers/devise.rb
# config.scoped_views = false
uncomment the line and change to "true":
config.scoped_views = true
Restart your application using rails server
in your terminal and go to registration page again. You will see the "Register" title this time.
Step 3: Run "Migration"
Great, we can now focus on adding more information to the user form. Before we modify the form we need to make sure our model can take it. At the moment our users can have an email and password, both were generated by Devise. We need to add "name" to the database table for users. We will do this with migration - a special file to update structure of the database. In bash:
bash
$: rails generate migration add_name_to_users name:string
invoke active_record
create db/migrate/20140519054104_add_name_to_users.rb
Step 4: Check and Modify Migration File
Let's make sure the generated file is correct. Make sure it looks like this:
db/migrate/20140519054104_add_name_to_users.rb
class AddNameToUsers < ActiveRecord::Migration
def change
add_column :users, :name, :string
end
end
At this point you can freely edit this migration file. For example, you can still add some other fields like gender or date of birth. We will include them here in case you'd like to do it as well. We will try to use different data formats:
class AddNameToUsers < ActiveRecord::Migration
def change
add_column :users, :name, :string
add_column :users, :date_of_birth, :datetime
add_column :users, :is_female, :boolean, default: false
end
end
Notice how we used boolean (true or false) value for gender instead of using string. Of course, if you want to allow more genders (for whatever reason) feel free to implement it in a different way.
Step 5: Migrate Database
We can now migrate our database:
bash
$ rake db:migrate
== 20140519054104 AddNameToUsers: migrating =======================
-- add_column(:users, :name, :string)
-> 0.0016s
-- add_column(:users, :date_of_birth, :datetime)
-> 0.0005s
-- add_column(:users, :is_female, :boolean, {:default=>false})
-> 0.0029s
== 20140519054104 AddNameToUsers: migrated (0.0052s) ==============
Step 6: Edit Users
We can now try editing our existing user. Let's start by adding a link to the page where we can edit user's profile:
app/views/layouts/_menu.html.erb
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<%= link_to "Demo App", root_path, class: 'navbar-brand' %>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><%= link_to 'Posts', '#' %></li>
<% if current_user %>
<li><%= link_to 'Edit Profile',edit_user_registration_path %></li>
<li><%= link_to 'Logout', destroy_user_session_path, method: :delete %></li>
<% else %>
<li><%= link_to 'Login', new_user_session_path %></li>
<% end %>
</ul>
</div>
</div>
</nav>
And add our new fields to this page:
app/views/users/registrations/edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :name %><br />
<%= f.text_field :name, autofocus: true %></div>
<div><%= f.check_box :is_female, {}, true %> <%= f.label :is_female, "Female" %> </div>
<div><%= f.check_box :is_female, {}, false %> <%= f.label :is_female, "Male" %> </div>
<div><%= f.label :date_of_birth %><br />
<%= f.date_select :date_of_birth %></div>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "off" %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %></div>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off" %></div>
<div><%= f.submit "Update" %></div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
<%= link_to "Back", :back %>
Step 7: Save information
Now, we can try to edit our profile with some more precise information and attempt to save.
After you save the information and go back to the page, you will find that none of the custom fields has been saved:
This is because the way Rails 4 deals with "mass assignment." Due to security reasons we have to explicitly permit parameters inside each controller. That also concerns the controllers build in the Devise. We won't be customizing them now, instead we will follow guidelines provided by Devise team and add permissions to application controller:
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :email, :password) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:name, :email, :password, :current_password, :is_female, :date_of_birth) }
end
end
Every time you want to edit permissions for our users, you would have to do it here. Notice how we're specifying permissions separately for sign ups and updating account. After you save those changes you can try editing your profile again. This time it will work.
Comments
Comment
You can login to comment
On: D wrote:
On: Brunitob wrote:
Im having some problem with heroku, I get: We're sorry, but something went wrong.
On: Suresh Kumar R wrote:
Hi
Could you please the gender (male and female) as radio buttons please instead of check boxes?
On: Suresh Kumar R wrote:
Hi Lucasz,
Can I use radio buttons as follows?
On: Hendrix wrote:
Hola segui los pasos que indicaste y no me funciona el login ahora.
On: Giancarlo wrote:
Pero mi css se distorsiona!
On: Pablo wrote:
Hola que tal, seguí los pasos que indicas para agregar un nuevo campo pero cuando lo imprimo desde el controlador SessionsController me sale vacío, si imprime el correo y la clave encriptada pero el campo que agregue no. Por favor Ayuda...
On: carolina wrote:
Hola!! gracias por los tutoriales están muy buenos!!!, pero no me esta generando los campos que agregue al formulario no realiza ningún cambio como el titulo, cambie el nombre pero sigue igual que puede ser? estoy usando ruby 2.0.0 y rails 4.2.4
On: Armando wrote:
Excelente tutorial, claro y preciso. Gracias!!!
On: Tunde Adetula wrote:
i have validated the custom fields i want in my users but now when i try to signup, it keeps asking me for that validation i.e DOB no present is there a way around that that please. A way to exempt DOB when user wants to sign up
On: Roy wrote:
Buenisimo!!! gracias xD!!!
On: Carles Bas wrote:
Para Rails 4 han cambiado algunos parámetros para application_controller
The Parameter Sanitaizer API has changed for Devise 4 class ApplicationController < ActionController::Base beforeaction :configurepermittedparameters, if: :devisecontroller?
protected
def configurepermittedparameters
end end
via: stackoverflow