Setting up multiple devise registrations controllers? - ruby-on-rails

I have a devise user model and devise admin model, each one has nested attributes and therefore I need to overwrite each separate model to amend the strong parameters so that my nested attributes will pass through.
How do I go about doing this? I already have overwritten Registrations controller for one of them and its working perfectly, however, If I replicate it and have the controller name as AdminregistrationsController < Devise::RegistrationsController (because of course I can't have two called RegistrationsController) then it doesn't work.
Any advice would be great.

If you have, lets say user and admin models, you do the following:
controllers/users/registration_controllers.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def new
build_resource({})
#self.resource.regions.build
#respond_with self.resource
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username << :gender << :email << :password_confirmation << :password << :roles_mask << :phone << :first_name << :last_name << :googleplus
end
end
controllers/admins/registration_controllers.rb
class Admins::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def new
build_resource({})
#self.resource.regions.build
#respond_with self.resource
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username << :email << :password_confirmation << :password << :roles_mask << :phone << :first_name
end
end
Obviously you need to change the parameter list, the above are just random examples. Hope this helps.

Considering #Georg Keferböck's answer and also improving it for devise 4
I would place the configured_permitted_parameters method in the applications controller because the parameters might definitely be required for more than one devise controller
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
if current_user
update_attrs = [:password, :password_confirmation,:current_password]
devise_parameter_sanitizer.permit :account_update, keys: update_attrs
else
update_attrs = [:password, :password_confirmation, current_password,
:phone]
devise_parameter_sanitizer.permit :account_update, keys: update_attrs
end
end
end
Users registration controller
class Users::RegistrationsController < Devise::RegistrationsController
...
...
end
Admins registration controller
class Admins::RegistrationsController < Devise::RegistrationsController
...
...
end
Ofcourse you would have to use the parameters configured for you own models

Related

How to permit params to a specific devise_controller with devise_token_auth gem?

I'm using devise_token_authentication gem to build token based authentication rails api, then after that I added some extra fields to Vendor model through different migration, and in order to permit them I wrote this:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :tax_number])
devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :tax_number])
end
end
Then after that I added another model Customer rails g devise_token_auth:install Customer auth
then in routes.rb
Rails.application.routes.draw do
mount_devise_token_auth_for 'Vendor', at: 'vendor/auth'
mount_devise_token_auth_for 'Customer', at: 'customer/auth'
end
each time I try to sign_up with customers through 'localhost:3000/customer/auth' I got error message: ActiveModel::UnknownAttributeError: unknown attribute 'tax_number' for Customer.
So is there any way to permit the extra fields only for Vendor model and skip 'Customer' ?
look on this setup for multiple devise user models.
or
If you override the RegistrationsController you need to permit extra params directly in registrationsController
class Users::RegistrationsController < DeviseTokenAuth::RegistrationsController
def create
end
def account_update
end
private
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, :first_name, :last_name, :tax_number)
end
end

Devise update_without_password gives ForbiddenAttributesError

I added additional fields to my user model, then updated the configure_account_update_params method accordingly. Everything was working until I wanted users to be able to update their information without having to input their current password.
So I removed the field for the view and changed the update method in the RegistrationsController
This is my controller, I'm not sure if I'm missing something
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_account_update_params, only: [:update]
def update
resource.update_without_password(resource_params)
end
# If you have extra params to permit, append them to the sanitizer.
def configure_account_update_params
devise_parameter_sanitizer.for(:account_update) << [:first_name, :last_name, :country, :phone_number, :gender, :birthdate]
end
end
According to devise documentation, you should replace this in your controller.
class Users::RegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
end

Additional parameters for devise model on sign up

I am using Devise for my users in my rails app. When people sign up its only their email and password. How do I have access to the controller to permit more param such as first name and last name?
Thank you
You should add the parameters to the devise_parameter_sanitizer for sign_up
This can be done in your application_controller.rb
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :first_name
end
end
or configure the whole set of parameters using
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:password, :password_confirmation, :email, :first_name, :last_name) }
end
Another way is to create a class that inherits from Devise::ParameterSanitizer
class User::ParameterSanitizer < Devise::ParameterSanitizer
def sign_up
default_params.permit(:password, :password_confirmation, :email, :first_name, :last_name)
end
end
Then in your application_controller.rb
class ApplicationController < ActionController::Base
protected
def devise_parameter_sanitizer
User::ParameterSanitizer.new(User, :user, params)
end
end

Saving other attributes to User model with Devise gem

I have created a User model through the Devise gem that allows email, first_name, and password upon registration.
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :first_name
end
I would like to save other attributes such as last_name, city, etc to the User model. I have ran the migrations and see these attributes in my schema.
However when I am on the user/edit page and try to save, the new attributes are not saving.
I have run the command to edit the devise controllers, but confused.
rails generate devise:controllers users
Do I still need to create a UsersController < ApplicationController in order to accept other attributes into the User model during an edit/update?
Then I could just permit all when trying to update
def user_params
params.require(:user).permit!
end
Thanks
Try this:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:user) << :first_name
end
end
Add the following filter to the application controller:
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit( :first_name, :email, :password, :password_confirmation) }
end
This is for sign up. To update the user informaiton add following line of code within the configure_permitted_parameters filter.
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:first_name, :email, :password, :password_confirmation, :current_password) }

Adding extra registration fields with Devise

I am trying to add some extra fields to registrations#new. Since I only want extra data and do not need different functionality, I don't see why I need to override controllers etc. So what I did was modify registrations#new as follows:
%h2
Sign up
= 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
= f.label :title_id
%br
= f.text_field :title_id
%div
= f.label :province_id
%br
= f.text_field :province_id
%div
= f.label :first_name
%br
= f.text_field :first_name
%div
= f.label :last_name
%br
= f.text_field :last_name
%div
= f.label :password
%br
= f.password_field :password
%div
= f.label :password_confirmation
%br
= f.password_field :password_confirmation
%div= f.submit 'Sign up'
= render 'devise/shared/links'
To enable these extra fields through the sanitizer, I updated ApplicationController as follows:
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 :store_requested_url!
# before_filter :authenticate_user!
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:email) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation, :title_id, :province_id, :first_name, :last_name) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:email, :password, :password_confirmation, :current_password) }
end
def after_sign_in_path_for(resource)
session[:requested_url] || root_path
end
private
def store_requested_url
# store last url as long as it isn't a /users path
session[:previous_url] = request.fullpath unless request.fullpath == /\/users/
end
end
For some reason, it is not working and the extra fields go to the database as nulls.
I am using Ruby 2 and Rails 4 rc1, with Devise 3.0.0.rc.
It would appear that the code sample in your question is not working because you are not setting the before_filter to call the sanitizer.
before_filter :configure_permitted_parameters, if: :devise_controller?
With that said, it's probably better to override the controller, as shown in the accepted answer, so that the application controller isn't doing this check all of the time. The accepted answer can be shortened up with the code below. I've tested this code with my application and it works well. All of this is documented in the Strong Parameters section of the README in the 3.0.0.rc tag.
Override the controller:
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters, :only => [:create]
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password) }
end
end
Then update the routes to use it:
devise_for :members, :controllers => { :registrations => "registrations" }
As of Devise version 4.3.0, May 15th 2017, the solution is as follows from the documentation. In this case, the username field is being added.
In case you want to permit additional parameters (the lazy way™), you can do so using a simple before filter in your ApplicationController:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
And of course, simply add the field to your database
> rails g migration AddUsernameToUsers
class AddUsernameToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :username, :string, null: false, index: true, unique: true
end
end
And then add the necessary fields into the view for registrations#new
<%= f.text_field :username, placeholder: "Username" %>
After Devise 4.0 the older answers on this topic are not valid. instead of the for method you have to use:
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
So, for a complete solution in ApplicationController:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
OK, so what I did was just override the Devise registration controller, update routes.rb as per the devise docs to reflect this, copied and pasted the Devise code for registrations#create as is, and change the getting params part to use my own strong parameters method, and that was that.
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(registration_params)
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
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}" if is_navigational_format?
respond_with resource, :location => after_sign_up_path_for(resource)
end
else
clean_up_passwords
respond_with resource
end
end
private
def registration_params
params.require(:user).permit(:email, :title_id, :first_name, :last_name,
:province_id, :password, :password_confirmation)
end
end
First expose the views
rails generate devise:views users
then edit config/initializers/devise.rb and change
# config.scoped_views = false
to
config.scoped_views = true
this will allow you to modify the views at app/views/users/registration.
you will add the fields needed here, in both
app/views/users/registration/edit.html.erb
app/views/users/registration/new.html.erb
Now we have to deal with rails mass assignment issue, go to application_controller.rb and add a before_filter
before_filter :configure_permitted_parameters, if: :devise_controller?
then add your fields + original fields to devise sanitization
protected
def configure_permitted_parameters
# Fields for sign up
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password) }
# Fields for editing an existing account
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :current_password, :gender) }
end
restart your web server and cross your fingers.
I've had similar situation (just fields were different).
Here's the way official documentation can offer:
Just add this to your ApplicationController. And change "username" to whatever you need, and add some more if you need.
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
My Applications Controller looks like that:
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_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :public_name
end
end
More details here: https://github.com/plataformatec/devise ("Strong Parameters")
First: Isn't there a new 'strong parameters' issue with rails 4, you might want to look into this as well.
If you migrate the new parameters into your User model. Then all you have to do is to override (create) the files:
app/views/devise/registrations/edit.html.erb
app/views/devise/registrations/new.html.erb
you can look at the default files here:
https://github.com/plataformatec/devise/tree/master/app/views/devise/registrations
IF you might want to implement an own registrations_controller.rb (with actions new and edit) and your own #variables then it is important to add this in your routes.rb
devise_for :users, :controllers => { :registrations => 'registrations' }
resources :users
This ensures, that devise takes your new 'registrations' controller from now on (if you decided to have one).
I don't know "sanitizer" or what this is good for. But my App works just fine with those minor changes I just recommended to you. You don't need to override the Controller! Overriding the Views will just be enough.
New fields could be added like this example. For Devise 4, the Parameter Sanitaizer API has changed:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :name])
end
end

Resources