Unpermitted Parameters adding new fields to Devise in rails 4.0
Ruby on-RailsRubyRuby on-Rails Problem Overview
Very new to working with rails. I have implemented a basic login system using Devise. I am trying to add a couple of new fields (bio:string, name:string) into the sign_up page. I have everything displaying correctly and the new fields are added to the database (when I view it in SQLbrowser) however, they are not populating and after the user submits the sign_up form there is a message which part of it says:
Unpermitted parameters: bio, name
I have added the 2 strings to the _devise_create_users.rb
# added
t.string :bio
t.string :name
And I have them showing up in the schema.rb
ActiveRecord::Schema.define(version: 20130629002343) do
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "shortbio"
t.boolean "admin", default: false
t.string "realname"
t.string "name"
t.string "bio"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
My user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
#:token_authenticatable, :confirmable,
#:lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Is this problem something to do with Strong Parameters? I am having a hard time wrapping my head around them and where/how to implement.
Ruby on-Rails Solutions
Solution 1 - Ruby on-Rails
The accepted solution is good enough, but I see two problems: 1) All the controllers will check if the current controller is the devise controller (if: :devise_controller?
) and 2) We need to write all the acceptable parameters in the method (...for(:sign_up) {|u| u.permit(:bio, :name)}
), even the :email
, :password
and so on.
I think that a more elegant solution could be:
# app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up).push(:name, :phone, :organization)
end
end
# config/routes.rb
devise_for :users, :controllers => { :registrations => "users/registrations" }
NOTE: Updates for Rails 4.2+
This answer is falling out of date:
- Change "users" to "user" in the "users/registration" path for Rails 4.2.1 and Devise 3.4.1.
devise_parameter_sanitizer.permit()
replacesdevise_parameter_sanitizer.for()
for Devise 4 (see https://stackoverflow.com/questions/37341967/rails-5-undefined-method-for-for-devise-on-line-devise-parameter-sanitizer)
Solution 2 - Ruby on-Rails
Make sure you are using Devise 3.0.0 at least. Add to your application controller:
before_filter :update_sanitized_params, if: :devise_controller?
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:bio, :name)}
end
Documentation: https://github.com/plataformatec/devise#strong-parameters
Solution 3 - Ruby on-Rails
I was having trouble with this too. The documentation on devise's site helped as well as some forums. Here's what I ended up doing:
In custom RegistrationsController (app/controllers/users/registrations_controller.rb)
# app/controllers/users/registrations_controller.rb
class Users::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, :password, :password_confirmation)}
end
end
Then in your route file (config/routes.rb) us this for your devise_for statement:
devise_for :users, controllers: {registrations: "users/registrations"}
Solution 4 - Ruby on-Rails
Here's another straight forward way that works in my rails 4.2.1 app:
Create the following file
/config/initializers/devise_permitted_parameters.rb
and the code..
module DevisePermittedParameters
extend ActiveSupport::Concern
included do
before_filter :configure_permitted_parameters
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
devise_parameter_sanitizer.for(:account_update) << :name
devise_parameter_sanitizer.for(:sign_up) << :bio
devise_parameter_sanitizer.for(:account_update) << :bio
end
end
DeviseController.send :include, DevisePermittedParameters
Solution 5 - Ruby on-Rails
For both sign_up and account_update do this for controllers/applcation_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:password, :password_confirmation,:current_password,:email,:name, :phonenumber,:province,:city,:area,:idcardimg,:role) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:password, :password_confirmation,:current_password,:email,:name, :phonenumber,:province,:city,:area,:idcardimg,:role) }
end
end
Solution 6 - Ruby on-Rails
The problem seems with the strong parameters, look here and copy the code.
Copy that file to the same location in your project app/controllers/devise/registrations_controller.rb
and change the code of the create action
# POST /resource
def create
# THIS LINE IS THE ONE YOU CHANGE
self.resource = build_resource(sign_up_params.merge(:bio, :name))
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?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
I must tell you that Iam not pretty sure if this works because I don't use devise but seeing the code it seems it will work.
Solution 7 - Ruby on-Rails
Devise prepared everything for that :
In the users controller you have
private
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:full_name <add your parameter>)
end