Related
I'm using a user scope controller generated by devise to pass additional attributes.
class Users::RegistrationsController < Devise::RegistrationsController
before_action :sign_up_params, only: [:create]
before_action :account_update_params, only: [:update
protected
def sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :cpf])
end
def account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :cpf, :birth_date, :phone, :gender])
end
def update_resource(resource, params)
resource.update_without_password(params)
end
end
The routes
devise_for :users, controllers: {registrations: 'users/registrations}
Everything was working until include the update_resource(resource, params) method to the controller and remove the current_password field at the view, as suggested https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-account-without-providing-a-password
After this change I can edit every additional fields (first_name, last_name...etc) except the password. The password change doesn't persists. Any idea?
Rails version: 5.0.0.1
Devise version: 4.2.0
In the account_update_params method you need to add your password and password_confirmation.
def account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :cpf, :birth_date, :phone, :gender, :password, :password_confirmation])
end
I have been stuck up with this exception.I am using rails 4.2.5.1 and ruby 2.3.0. I am creating a model using devise in rails. I have override the devise create method. I am getting error in postgres as PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraint.I want the ID to be created with the help of parameters i am passing. ID is not getting created. As am new to rails am getting stuck up for hours now.
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"SAiVJEULEa7RsieW+OTW1a/946f2xVbhA/sZWWn3KdX1Wt0Ozx+tq6eQfhTpaAJ+4Cxu2DMnPfqd0Vcle7ow0w==",
"employee"=>{"email"=>"safi123#gmail.com",
"first_name"=>"sss",
"last_name"=>"dddnjnfj",
"phone_number"=>"9944253677",
"alternative_phone_number"=>"9659392682",
"alternative_email_id"=>"dd#gmail.com",
"date_of_joining"=>"12-02-2015",
"date_of_birth"=>"03-02-1999",
"status"=>"Active",
"gender"=>"M",
"blood_group"=>"A +"},
"commit"=>"Sign up"}
Application Controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_employee!
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |employee_params|
employee_params.permit :first_name, :last_name, :blood_group, :phone_number, :gender, :date_of_birth, :email, :alternative_email_id, :status, :date_of_joining, :alternative_phone_number
end
devise_parameter_sanitizer.for(:account_update) do |employee_params|
employee_params.permit :first_name, :last_name, :blood_group, :phone_number, :gender, :date_of_birth, :email, :alternative_email_id, :status, :date_of_joining, :alternative_phone_number
end
end
end
Registrations Controller
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def index
#employees = Employee.all
end
def create
#employee = Employee.new(employee_params)
if #employee.save
redirect_to :action => :new
else
render 'new'
end
#employee.save
end
# Never trust parameters from the scary internet, only allow the white list through.
def employee_params
params.require(:employee).permit(:first_name, :last_name, :blood_group, :phone_number, :gender, :date_of_birth, :email, :alternative_email_id, :status, :date_of_joining, :alternative_phone_number)
end
def update
super
end
end
Database schema :
I can understand the ID is not generated and it is not stored in the database. What is the problem here? Can anyone explain me what is the mistake am making?
You are saving the employee record twice. That may be the problem, please save only once.I have given the action please check.
def create
#employee = Employee.new(employee_params)
if #employee.save
redirect_to :action => :new
else
render 'new'
end
/* Here you had saved again. */
end
Your Employee params,
def employee_params
params.require(:employee).permit(:first_name, :last_name, :blood_group, :phone_number, :gender, :date_of_birth, :email, :alternative_email_id, :status, :date_of_joining, :alternative_phone_number)
end
Now you will get the id through params and it will be saved.
I made a devise User model and added additional fields to it. When I create and account everything works fine, only with email, pw and pw conf.
I then want to allow the user to go to edit page and fill in the optional additional fields.
But, when they submit, everything is saved as nil.
class RegistrationsController < Devise::RegistrationsController
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in){ |u| u.permit(:email, :password) }
devise_parameter_sanitizer.for(:sign_up){ |u| u.permit(:name, :username, :about, :email, :password, :password_confirmation)}
devise_parameter_sanitizer.for(:account_update){ |u| u.permit(:name, :username, :about, :email, :password, :password_confirmation) }
end
def update
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
if resource.update_with_password(user_params)
if is_navigational_format?
flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ? :update_needs_confirmation : :updated
set_flash_message :notice, flash_key
end
sign_in resource_name, resource, :bypass => true
respond_with resource, :location => after_update_path_for(resource)
else
clean_up_passwords resource
respond_with resource
end
end
def user_params
params.require(:user).permit(:email, :password, :current_password, :password_confirmation, :name, :username, :about)
end
end
I get this output in the console,
ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by Devise::RegistrationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"EG8FtCTBohuG2uwUvIqmY7KTsmYY1nMAXqTfc0Li+eQ=",
"user"=>{"email"=>"a#a.com", "name"=>"Aaron", "username"=>"", "about"=>"",
"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}, "commit"=>"Update"}
User Load (2.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Unpermitted parameters: name, username, about
But nothing is saved in the database when I check in the console (with User.last). I am stuck, and have looked and have no idea what is wrong...
In Rails4 we have strong parameters so please
Add following line to your application_controller.rb
before_filter :configure_devise_params, if: :devise_controller?
def configure_devise_params
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:first_name, :last_name, :gender, :email, :password, :password_confirmation)
end
end
After working on something similar to this, I settled on using Application Controller, then afterward found that the Devise Documentation is fairly straightforward for this in their strong parameters section and gives an alternative to using Application Controller. https://github.com/plataformatec/devise#strong-parameters
Below is the approach with Application Controller which worked for me.
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up){ |u| u.permit(:name, :username, :about, :email, :password, :password_confirmation)}
devise_parameter_sanitizer.for(:account_update){ |u| u.permit(:name, :username, :about, :email, :password, :password_confirmation) }
end
end
This should work the same and it directly overwrites methods in Devise::RegistrationController.
class Users::RegistrationsController < Devise::RegistrationsController
private
def configure_sign_up_params
devise_parameter_sanitizer.for(:sign_up){ |u| u.permit(:name, :username, :about, :email, :password, :password_confirmation)}
end
def configure_account_update_params
devise_parameter_sanitizer.for(:account_update){ |u| u.permit(:name, :username, :about, :email, :password, :password_confirmation) }
end
end
First produce new field.
for reference
http://guides.rubyonrails.org/migrations.html
Do you have add your new fields in user controller parameter?
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
In the application controller
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation)}
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:email, :password, :password_confirmation)}
end
In your registration form that override devise add this
class Users::RegistrationsController < Devise::RegistrationsController
skip_before_filter :verify_authenticity_token, :only => [:ipn_notification]
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
After that add your new fields in all views _form,show,edit,index.
In Rails 4.2, this is how I did.
I have User Model on which devise is applied.
Use this command "rails generate devise:controllers users" to generate custom controllers.
I have added "username" name attribute to my User Model
In my controller
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_sign_up_params, only: [:create]
before_filter :configure_account_update_params, only: [:update]
#rest of code as generated
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.for(:sign_up) << :username
end
# If you have extra params to permit, append them to the sanitizer.
def configure_account_update_params
devise_parameter_sanitizer.for(:account_update) << :username
end
In Routes
devise_for :users, controllers: {registrations: "users/registrations"}
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
Trying to add a nested custom attribute, Profile (a Mongoid document), to my devise User class. When the Devise registration form is submitted, it should create both a User and a corresponding Profile object as well.
I'd like the end-result to look something like this in my MongoDB:
User:
{
# Devise fields:
"email": "my#email.com",
...
# Custom field
"profile" : "<object_id>"
}
Profile:
{
"first_name": "Dave",
....
}
Unfortunately, I am receiving this in my console whenever I submit my registration. It successfully creates a User but fails to create an associated Profile.
Started POST "/" for 127.0.0.1 at 2013-04-20 23:37:10 -0400
Processing by Users::RegistrationsController#create as HTML
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"awN2GU8EYEfisU0",
"user"=>
{"profile_attributes"=>
{"first_name"=>"Dave",
"birthday(2i)"=>"4",
"birthday(3i)"=>"21",
"birthday(1i)"=>"1933",
"occupation_title"=>"Software Developer"},
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"email"=>"my#email.com"}}
Unpermitted parameters: profile_attributes
I have setup:
Rails 4.0.0beta1, Ruby 2.0.0-p0
Devise ('rails4' branch), Mongoid (from git)
A custom Devise registrations controller to add a definition for strong parameters.
models/user.rb:
class User
include Mongoid::Document
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:token_authenticatable, :confirmable, :lockable, :timeoutable
field :email, type: String, default: ''
...
has_one :profile
accepts_nested_attributes_for :profile
end
models/profile.rb:
class Profile
include Mongoid::Document
include Mongoid::Timestamps
# Attributes
# ----------
field :slug, type: String, default: '' # Acts as user-'friendlier' slug
field :birthday, type: DateTime, default: DateTime.now
field :first_name, type: String, default: ''
field :occupation_title, type: String, default: ''
belongs_to :user
embeds_many :photos
has_one :occupation_industry, :as => :industry
end
controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
def resource_params
params.require(:user).permit(:email, :password, :password_confirmation, :profile_attributes)
end
private :resource_params
end
routes.rb
devise_for :users,
:path => '',
:path_names => {
:sign_in => 'login',
:sign_out => 'logout',
:sign_up => 'register'
},
:controllers => {
:registrations => "users/registrations",
:passwords => "users/passwords"
}
I have already looked at these related posts, they didn't seem to help:
Rails 4 Nested Attributes Unpermitted Parameters
https://gist.github.com/kazpsp/3350730
EDIT:
Looks like Devise does actually support strong parameters in its 'rails4' branch (which is supposed to be merged into master in a few days.) Looking through the code, it appears you can override a params function for each action on devise controllers. For creating new users, its sign_up_params instead of resource_params in my example.
Despite changing this name to the proper one, it still didn't work... only whitelisting all parameters using this bang seemed to work:
def sign_up_params
params.require(:user).permit!
end
Obviously, this kind of defeats the purpose of strong parameters... so now the question is how do I permit my nested attributes profile_attributes (as seen in my original question)?
I had the exact same issue and overriding sign_up_params did work for me
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, :other, :etc)
end
of course, the difference is in that mine are just scalar values, while you're trying to mass assign a relation... I guess that's where you should look for.
By the way, the documentations is still inexistint in this topic (too new), and code commnents suggest to override devise_parameter_sanitizer, which isn't necessary.
I found a different method that allows all the devise overriding logic and code to reside in the application controller. This allows any and all custom params to be passed through for each devise action (sign in, sign up, update). I also add a parameter sanitizer for devise_invitable and handle that logic here (invite, accept_invitation). I've got custom params like avatar, avatar_cache, etc:
#application_controller.rb
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
# There are just three actions in Devise that allows any set of parameters to be passed down to the model,
# therefore requiring sanitization. Their names and the permited parameters by default are:
# sign_in (Devise::SessionsController#new) - Permits only the authentication keys (like email)
# sign_up (Devise::RegistrationsController#create) - Permits authentication keys plus password and password_confirmation
# account_update (Devise::RegistrationsController#update) - Permits authentication keys plus password, password_confirmation
# and current_password. More at https://github.com/plataformatec/devise#strong-parameters
def configure_permitted_parameters
devise_parameter_sanitizer.for(:accept_invitation) do |u|
u.permit(:username,:validate_username, :password,:password_confirmation, :invitation_token)
end
devise_parameter_sanitizer.for(:invite) do |u|
u.permit(:name,:comments)
end
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:username,:password,:password_confirmation)
end
devise_parameter_sanitizer.for(:sign_in) do |u|
u.permit(:username,:email,:password,:password_confirmation,:phone, :validate_username, :avatar_cache, :remove_avatar, :current_password,:remember_me)
end
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:username,:email,:password,:password_confirmation,:phone, :validate_username,:avatar, :avatar_cache, :remove_avatar, :current_password)
end
end
Find and read more at https://github.com/plataformatec/devise#strong-parameters
I had the same issue when login, it says: Unpermitted parameters: password, remember_me.
and because i have any controller that inheriting Devise::SessionsController, so i use my own parameter sanitizer.
here is what i do:
Create a file in '#{Rails.root}/lib' fold, my is hzsapa_parameter_sanitizer.rb and required in config/application.rb, then override devise_parameter_sanitizer method in application_controller.rb
lib/hzsapa_parameter_sanitizer.rb
class HzsapaParameterSanitizer < Devise::ParameterSanitizer
def sign_in
default_params.permit(auth_keys + [:password, :remember_me])
end
end
You can override those method depends on your issue:
def sign_in
default_params.permit(auth_keys)
end
def sign_up
default_params.permit(auth_keys + [:password, :password_confirmation])
end
def account_update
default_params.permit(auth_keys + [:password, :password_confirmation, :current_password])
end
config/application.rb
require "hzsapa_parameter_sanitizer"
app/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
def devise_parameter_sanitizer
#devise_parameter_sanitizer ||= if defined?(ActionController::StrongParameters)
HzsapaParameterSanitizer.new(resource_class, resource_name, params)
else
Devise::BaseSanitizer.new(resource_class, resource_name, params)
end
end
end
Edit: i just found the solution in devise README, you can follow it here
I used your code and it worked for me!
Here is what I did
class RegistrationsController < Devise::RegistrationsController
skip_before_filter :verify_authenticity_token, :only => :create #, :if => Proc.new { |c| c.request.format == 'application/json' }
respond_to :json, :html, :xml
def create
user = User.new(devise_registrations_permitted_parameters)
if user.save
render :json=> user.as_json(:auth_token=>user.authentication_token, :email=>user.email,:name => user.name), :status=>201
return
else
warden.custom_failure!
render :json=> user.errors, :status=>422
end
end
protected
def devise_registrations_permitted_parameters
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end