Devise update_without_password gives ForbiddenAttributesError - ruby-on-rails

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

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

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

Editing custom fields in Devise User model

The fields were added via migration and the view's forms are created, but the controller filters the parameter on their path from the view to the model. No matter what I seem to do, my parameters are always unpermitted. My controller code
#app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_sign_up_params, only: [:create]
before_filter :configure_account_update_params, only: [:update]
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.for(:sign_up)<<[:first_name,:last_name,:profile_image,:graduation_year]
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,:profile_image,:graduation_year]
end
end
end
#config/routes.rb
Rails.application.routes.draw do
#...
devise_for :users, controllers: { account_update: "users/registrations", sign_up:"users/registrations" }
end
#Error
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Qts15L3n6Xvsn0hwNvIUI6UrWUQyV/qEyoQAZ8M+udMK1RBTQS1XoNWgpg1JrXqWpb9NbrsaHtQVVU8XMwoSIQ==",
"user"=>{"first_name"=>"a", "last_name"=>"a",
"profile_image"=>#<ActionDispatch::Http::UploadedFile:0x00000004fe0bb0 #tempfile=#<Tempfile:/tmp/RackMultipart20150709-4420-12guerh.jpeg>, #original_filename="test1.jpeg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"user[profile_image]\"; filename=\"test1.jpeg\"\r\nContent-Type: image/jpeg\r\n">,
"graduation_year"=>"1", "email"=>"aaaaaa#a.a",
"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"},
"commit"=>"Submit"}
Unpermitted parameters: first_name, last_name, profile_image, graduation_year
Thanks for the help everyone. Really appreciate it!
My config/routes.rb was messed up. It needed to be
devise_for :users, controllers: { registrations: 'users/registrations' }
Then I needed to add :email, :password, :password_confirmation back to app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_sign_up_params, only: [:create]
before_filter :configure_account_update_params, only: [:update]
def configure_sign_up_params
devise_parameter_sanitizer.for(:sign_up)<<[:first_name,:last_name,:profile_image,:graduation_year,
:email,:password,:password_confirmation]
end
def configure_account_update_params
devise_parameter_sanitizer.for(:account_update)<<[:first_name,:last_name,:profile_image,:graduation_year,
:email,:password,:password_confirmation]
end
end
Also there was an extra 'end' at the bottom of the file.
Update
In the current version of devise (4.3)/rails (5.1.3) it is similar, but the configure functions should be updated to something like this:
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :age, :height, :weight, :gender])
end
I had the same problem and changing like the below worked for me.
def configure_sign_up_params
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit( :first_name, :last_name, :profile_image, :graduation_year) }
end
def configure_account_update_params
devise_parameter_sanitizer.for(:account_update) { |u| u.permit( :first_name, :last_name, :profile_image, :graduation_year) }
end

Setting up multiple devise registrations controllers?

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

Strong parameters - Devise 3.0.0 and Rails 4. "Unpermitted parameters: name"

I am currently using Rails 4 and Devise 3.0.0. I have tried to add a custom field of "Name" to the sign up form and edit registration form. Whenever I submit the form, the following errors arise:
Unpermitted parameters: name
WARNING: Can't mass-assign protected attributes for User: email, password, password_confirmation.
I understand that this has something to do with the way Rails 4 handles parameters, but I do not understand what I am supposed to do about it right now. I have searched around and have seen that I am supposed to add some lines to a User model involving "params."
My user model currently looks like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, #:recoverable,
:rememberable, :trackable, :validatable
attr_accessible :name, :password, :password_confirmation, :remember_me, :email
end
According to How is attr_accessible used in Rails 4?, I am supposed to add the following code to "The controller."
class PeopleController < ApplicationController
def create
Person.create(person_params)
end
private
def person_params
params.require(:person).permit(:name, :age)
end
end
What controller? And is this literal code? Since I am dealing with User, do I have to use User.create(user_params)? instead of Person.create(person_params)?
Rails 4 has moved parameter sanitisation to the Controller from the Model. Devise handles it for 3 actions, sign_in, sign_up and account_update. For sign_up, the permitted parameters are authentication key (which is :email by default), password and password_confirmation.
If you want to add :name to the User model and use it for sign_up, either change config.authentication_keys = [ :email ] to config.authentication_keys = [ :name ] in /config/initializers/devise.rb or, if you want to use both :email and :name, add this to the ApplicationController
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
Also check-
https://github.com/plataformatec/devise#strong-parameters
You have to add this in controller where you have written User.create(user_params). I am assuming that UsersController.
class UsersController < ApplicationController
def create
User.create(user_params)
end
private
def user_params
#assumption: user params are coming in params[:user]
params.require(:user).permit(:name, :age, :and_other_params_you_want_to_allow)
end
end
Yes, you should add one line which is like:-
attr_accessible :name
in your model to allow name to assigned and if it does not work try this How is attr_accessible used in Rails 4?
I have similar problem. So, to fix it I created custom registration controller inherit form DeviseRegistration controller. Check Devise documentation and define controller like this.
class RegistrationsController < Devise::RegistrationsController
before_filter :update_sanitized_params, if: :devise_controller?
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:name, :email, :)}
end
end
Make sure you have define this routes for this controller in config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations" } , :path => '', :path_names => {
:sign_in => 'login',
:sign_out => 'logout'
}
Check this documentation of devise for strong parameter.
i had similar issues, this was my fix:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) { |u| u.permit!}
end
end

Resources