i am having two tables employee , and company. i want to register the company name of an employee while Employee is registering by using the devise sign_up action. how to write devise parameter sanitiser method to save the company name while an employee is registering?
The trick is using accepts_nested_attributes_for and overriding the sign_up_params
method on the registrations controller.
class User < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
# config/routes.rb
Rails.application.routes.draw do
# ...
devise_for :users, controllers: { registrations: "registrations" }
end
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
# GET /users/sign_up
def new
@user = User.new(company: Company.new)
end
def sign_up_params
params.require(:user).permit(
:email, :password, :password_confirmation,
company_attributes: [:name]
)
end
end
By digging into the source of Devise::RegistrationsController
we can se that it calls build_resource(sign_up_params)
which is about equivalent to User.new(sign_up_params)
. So we can simply add our own params handling by declaring our own sign_up_params
method.
Note that in sign_up_params
we use the built Rails 4 strong parameter handling instead of the Devise sanitized params which is a home rolled solution that predates Rails 4. It might be possible to do it with Devise sanitized params but there is no real reason unless you have to have backwards compatibility with Rails 3.
To get the correct params hash we want the company name input to have the following name
attribute:
user[company_attributes][name]
Rails has a nice helper called fields_for
which lets us do that:
<%# app/views/devise/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 class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<fieldset>
<legend>Company</legend>
<%= f.fields_for :company do |c| %>
<div class="field">
<%= c.label :name %><br />
<%= c.text_field :name%>
</div>
<% end %>
</fieldset>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
Notice that fields_for
gives us a new form builder instance in the block (c
) which we create our nested inputs from.