I'm writing a custom sign-up devise controller, and I'm having trouble adding permitted params due to this error (this is the output from Rspec, but the same error happens manually):
Failure/Error: devise_parameter_sanitizer.permit(:sign_up, keys: [:nome, :password, :password_confirmation, :cnpj, :razao_social, :nome_fantasia, :email, :tipo_entidade_id])
NoMethodError:
undefined method `concat' for #<Proc:0x0055ca9fb2d850>
Did you mean? concern
The full controller:
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
# POST /resource
def create
user_params = sign_up_params[:user_params]
entidade_params = sign_up_params[:entidade_params]
if !(User.exists?(email: user_params[:email]) || Entidade.exists?(cnpj: entidade_params[:cnpj]))
#entidade = Entidade.new(entidade_params)
#entidade.data_validade = 30.days.from_now
if #entidade.save
#user = User.new(user_params)
#user.entidade_id = #entidade.id
if #user.save
flash[:notice] = 'Usuario criado com sucesso.'
redirect_to root_path
end
end
end
end
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:nome, :password, :password_confirmation, :cnpj, :razao_social, :nome_fantasia, :email, :tipo_entidade_id])
end
end
At first glance it seems like a bug in the gem, but no one seems to have this issue - google returns nothing relevant. Is this an error in my code?
I'm not sure if it was the case, but this error can occur if you duplicate the parameters sanitizer, like using it in users controller but also in application controller.
You can see a more detailed explanation here:
GitHub issue closed
Related
am gonna add the error and also my controller where i think its the source of the error
I have tried different solutions, but none of them worked, the weird thing, my code was working this morning, and this error only occurs after I added new tables to the database
this is my controller
class UsersController < ApplicationController
before_action :configure_permitted_parameters, if: :devise_controller?
def create
#user = User.new(user_params)
if #user.save
redirect_to root_path, notice: 'Sign up successful.'
else
render :new
end
end
def index
#users = User.all
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:full_name, :password,
:password_confirmation])
end
end
and this is the error
Unpermitted parameters: :full_name, :password_confirmation. Context: { controller: Devise::SessionsController, action: new, request: #ActionDispatch::Request:0x00007fc5b5ca5a58, params: {"authenticity_token"=>"[FILTERED]", "user"=>{"full_name"=>"shaker abu drais", "email"=>"shaker_abady#yahoo.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up", "controller"=>"devise/sessions", "action"=>"create"} }
I have tried different solutions, but none of them worked, the weird thing, my code was working this morning, and this error only occurs after I added new tables to the database
What is it that you're actually trying to acheive here? If you're trying to just add additional attributes to the user registration then this code is just completely misguided.
You can whitelist additional attributes either through your ApplicationController which is the superclass for Devise's controllers:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:full_name, :password,
:password_confirmation])
end
end
Or by creating a subclass of Devise::RegistrationsController and configuring the routes if you need to customize the workflow further:
devise_for :user, controllers: { registrations: 'my_registrations' }
class MyRegistrationsController < ::Devise::RegistrationsController
before_action :configure_permitted_parameters, if: :devise_controller?
# Don't clobber the entire `#create` method. Especially not without actually
# replicating its functionality
def create
super do |user|
# do something with the newly registered user
end
end
private
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:full_name, :password,
:password_confirmation])
end
end
Note that I wouldn't call this controller UsersController. There is a reason why Devise choose the name Registrations - its because it differentiates between signing up and for example if users are created by an admin.
This is my usercontroller.rb
class UsersController < ApplicationController
before_action :user_logged_in, only: [:show,:edit ,:update, :index, :destroy]
before_action :check_admin, only: [:index]
before_action :check_correct_user, only: [:edit ,:update]
def edit
#user=User.find(params[:id])
end
This is update method
update
def update
#user=User.find(params[:id])
if #user.update(user_req)
flash[:success]="Profile Updated"
redirect_to #user
else
render 'edit'
end
this is params
private
def user_req
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
i created another method for check_admin
def check_correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless #user == current_user ||
current_user.admin?
end
end
I am not sure if I understand our question correctly. Do you want users to be able to update their own name, email, and password? And admins should be able to update other users too, but only their names?
Then I would do it like this:
def user_req
if current_user.admin? && #user != current_user
params.require(:user).permit(:name)
else
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
The condition is a bit more complex than expected because an admin user still needs to be able to update their own email and password.
I am using devise for my clients authentication, however, when I hit the sign up button in my view it throws me that I am already signed in, how so? I don't even have users in my database.
routes.rb
Rails.application.routes.draw do
devise_for :clients, controllers: { registrations: 'clients/registrations', sessions: 'clients/sessions' }
root to: "mainpages#index"
get '/mainpages', controller: 'mainpages', action: 'index'
get '/planes', controller: 'planes', action: 'planes'
resources :planes
My controllers are inside of controllers/clients, At the moment I want to activate all the related with registration and sessions, so here's my registration controller
registrations_controller
class Clients::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
# GET /resource/sign_up
def new
super
#client = Client.new
end
# POST /resource
def create
super
#client = Client.new(client_params)
#Set user perms to provider or to client
if #client.perms == false
#client.perms = "Client"
else
#client.perms = "Provider"
end
#client.status = "Not activated"
if #client.save
return redirect_to :root
end
render 'new'
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
end
# The path used after sign up.
def after_sign_up_path_for(resource)
super(resource)
end
private
def client_params
params.require(:client).permit(:name, :last_name, :email, :country, :username, :city, :address, :date, :perms, :status)
end
end
sessions_controller
# frozen_string_literal: true
class Clients::SessionsController < Devise::SessionsController
# before_action :configure_sign_in_params, only: [:create]
# GET /resource/sign_in
def new
super
end
# POST /resource/sign_in
def create
super
end
# DELETE /resource/sign_out
def destroy
super
end
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_in_params
devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute])
end
end
index.html.erb views/mainpages/
<div class="col-sm-6"><h4>Not a member?</h4>
<%= link_to '<p>You can create an account:</p>'.html_safe, controller: "clients/registrations", action:"new" %>
<p class="text-center">
<%= link_to '<i class="fas fa-sign-in-alt big-icon"></i>'.html_safe, controller: "clients/registrations", action:"new" %>
</p>
</div>
I tried to manually sign out by typing localhost:3000/clients/sign_out but I get a routing error, my link to the sign up page doesn't work if I don't get rid of that session, tried to restart the server but I still get the same error.
I've been trying to customize the devise register method to register with more parameters and also update more(no luck so far), but I always get Unpermitted parameters: error. I tried using this Adding extra registration fields with Devise and https://github.com/plataformatec/devise#strong-parameters, but I cant get over that.
I've also thought about creating a new table to hold a foreign key the user id and put in there stuff like user_id, display_name, profile_picture, but I would have the same problem when trying to submit everything from the same page(mess with the devise controller).
Do you have any suggestions on how I can solve this? What else do I have to post?
routes.rb
devise_for :users, controllers: { registrations: 'users/registrations' }
users/regC
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_paramss
params.require(:user).permit(:email, :display_name, :terms_of_services, :profile, :password, :password_confirmation)
end
Looks like you just need to tell devise which parameters should be permitted. By default, devise permits the email (or username depending on configuration), password and password_confirmation params. You just need to add more.
The devise documentation suggests a "lazy way" of setting this up.
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:display_name])
end
end
The documentation then says that
If you have nested attributes (say you're using accepts_nested_attributes_for), then you will need to tell devise about those nestings and types.
Only if you need to override the registrations#create action you should provide your custom route for devise. In that case, make sure you override the sign_up_params method too.
class Users::RegistrationsController < Devise::RegistrationsController
def create
# Your custom code here. Make sure you copy devise's functionality
end
private
# Notice the name of the method
def sign_up_params
params.require(:user).permit(:display_name, :email, :password, :password_confirmation)
end
end
In essence, you'd have to look into how your sign up form is posting the parameters to figure out how to configure strong parameters in the controller. Make sure you read on strong parameters syntax as well.
Hope it helps!
For Devise 4.2.0 you can whitelist additional parameters for your users table by adding those values to keys. By default devise gives you the comment to go off of now. Below I added :avatar
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute, :avatar])
end
The accepted answer says the config should go in your applicationController but it can simply go in your user registration controller and you can specify that you only want to run it for create method and nothing else:
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:enter_param_name_here])
end
end
In my case this worked:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:account_update) { |u| u.permit(:name, :last_name, :image,:email, :password, :password_confirmation, :current_password) }
end
end
I current use Rails 4 and I move the app from attr_accessible to the StrongParams. So, I have customised Devise controller:
class UsersController < Devise::RegistrationsController
load_and_authorize_resource
#...
def update
unless #user.userable?
if params[:selected_person_type] == I18n::t('activerecord.attributes.user.individual')
redirect_to new_individual_path and return
elsif params[:selected_person_type] == I18n::t('activerecord.attributes.user.legal_entity')
redirect_to new_legal_entity_path and return
end
end
#avatar = params[:avatar_id].present? ? Avatar.find_by(id: params[:avatar_id]) : #user.avatar
if params[:user][:password].blank?
if #user.update_without_password(user_params)
notice = if #user.unconfirmed_email.present? && Date.today == #user.confirmation_sent_at.to_date
t('devise.confirmations.send_instructions')
else
t('views.messages.notices.personal_data_updated')
end
redirect_to edit_user_path(#user), notice: notice and return
end
else
if #user.valid_password?(params[:user][:current_password])
params[:user].delete("current_password")
if #user.update_attributes(user_params) && #user.save
sign_in(#user, bypass: true)
redirect_to edit_user_path(#user), notice: t('views.messages.notices.personal_data_updated') and return
end
else
#user.errors.add(:current_password, :invalid)
end
end
render action: "edit"
end
def create
if resource.save
SystemMailer.send_mail(to: resource.email, body: resource.temp_password, subject: I18n.t('mailers.password.new')).deliver if resource.generate_password == '1'
if request.xhr?
expire_data_after_sign_in!
respond_to do |format|
format.js
end
else
super
end
else
if request.xhr?
clean_up_passwords(resource)
respond_to do |format|
format.js
end
else
super
end
end
end
private
def user_params
if current_user.present?
params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
end
end
end
I got the error before:
Failure/Error: post :create, user: attributes_for(:unconfirmed_user)
ActiveModel::ForbiddenAttributesError:
ActiveModel::ForbiddenAttributesError
This is because CanCan isn't so compatible with StrongParams, so i tried this fix in ApplicationController:
class ApplicationController < ActionController::Base
include SimpleCaptcha::ControllerHelpers
include CaptchaHelper
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :cancan_workaround
rescue_from CanCan::AccessDenied do |e|
redirect_to '/', flash: { error: I18n.t('views.messages.notices.access_denied') }
end
private
def cancan_workaround
resource = controller_name.singularize.to_sym
method = "#{resource}_params"
params[resource] &&= send(method) if respond_to?(method, true)
end
end
After that fix i got that error:
UsersController should successfully create user
Failure/Error: post :create, user: attributes_for(:unconfirmed_user)
NoMethodError:
undefined method `permit' for nil:NilClass
# ./app/controllers/users_controller.rb:75:in 'create'
# ./spec/controllers/users_controller_spec.rb:10:in `block (3 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:9:in `block (2 levels) in <top (required)>'
Here is ./app/controllers/users_controller.rb:75:in 'create' is super call in the action. Any idea how to fix that?
Devise
Devise doesn't work like other Rails input systems - it uses its own backend functionality to process the params. It seems devise automatically permits the email & password params, and its your job to add the other params its parameter_sanitizer
Devise and Strong Parameters
Bottom line is that, according to the Devise documentation, you'll have to use something like this:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
Ok, i got it. Problem was not in Devise, it was with my permissions:
private
def user_params
if current_user.present?
params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
end
end
Test evaluated for non-signed user, so when cancan's hook tried to execute this method:
params[resource] &&= send(method) if respond_to?(method, true)
It received nil, because user wasn't signed-in, so hook transformed :user => { ... } into the :user => nil. So, i fixed it via removing current_user.present?.
private
def user_params
params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
end
Not sure how well this solution is secure.