53

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.

r-s
  • 1,035
  • 2
  • 11
  • 21
  • 13
    @mohamad That's not really helping him solve the problem. – simonmorley Jun 29 '13 at 21:04
  • 5
    @simonmorley indeed. But it's a comment, not an answer. – Mohamad Jun 29 '13 at 21:45
  • 5
    Sometimes the best solution to a problem is simply a different approach, I appreciated the comment. – r-s Jun 29 '13 at 22:02
  • Devise is great if you want to use all more than just one or two of its features. Basic authentication is super easy to build from scratch and is often all you need. But once you get into "remember me" tokens, confirmation emails, forgot password, login/logout logging, and locking out accounts due to too many password attempts, devise starts to show its strengths! – stereoscott Jun 30 '13 at 07:42
  • I'd go with Mohamads recommendation. For a simple login system at least. Maybe the remember me, locking and so on features could convince me to use Devise again... but i've spent more time configuring Devise than writing things from scratch. If you write it yourself, look at http://apidock.com/rails/ActiveModel/SecurePassword/ClassMethods/has_secure_password and make sure you know what you are doing. The downside of rolling your own solution is that you might introduce security flaws (which might be in devise as well but it's more likely that somebody will discover them) – Pascal Jun 12 '14 at 19:22
  • 1
    I put most of my additional fields into another model `Profile` and circumvented most of the issues people are complaining about here. An additional model is arguably better database/model design anyway, though I won't try to argue that here. – Jeff Sep 16 '14 at 15:41

7 Answers7

71

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:

Community
  • 1
  • 1
Pablo Torrecilla
  • 2,098
  • 20
  • 15
  • The above gave me: `undefined method 'push' for #`. Any ideas? – MPV Feb 21 '15 at 09:20
  • 1
    devise_parameter_sanitizer.for gave me an error but using devise_parameter_sanitizer.permit(:sign_up, keys: [model parameters] worked for me -- http://www.rubydoc.info/github/plataformatec/devise/Devise/ParameterSanitizer – Kwestion Sep 09 '16 at 21:40
  • @doub1ejack: do you have a working example with the `permit` syntax so we can update the answer with the correct Rails 4 code? I think it should be like: `devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :phone, :organization])` – Pablo Torrecilla Nov 21 '16 at 19:17
  • I see many questions addressing the sign up portion of the registrations controller, but if you want to have this apply to editing a user, you need to replace :sign_up with :account_update. I'll just say that this is an absolute nightmare to figure out. Great answer. – sakurashinken Sep 22 '17 at 06:14
40

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

Pedro Nascimento
  • 13,136
  • 4
  • 36
  • 64
  • 1
    This still gives me the same "unpermitted parameters". I thought this would work for sure after reading more. – r-s Jun 29 '13 at 20:42
  • same problem still. this is my application_controller: https://gist.github.com/r-s-/5892634 – r-s Jun 29 '13 at 20:55
  • Thank you Pedro. I think I have got it now. I just had to add all the parameters that I needed to pass to that function, I am not sure if this is secure though. https://gist.github.com/r-s-/5892670 – r-s Jun 29 '13 at 21:09
  • If you need to permit them on sign_up, then yes. Just make sure they are all parameters which you would allow user input, i.e. Do not permit an admin key. – Pedro Nascimento Jun 30 '13 at 05:54
  • FYI, Devise documentations calls this "the lazy way". Answer below shows a way to do this without altering your application wide controller. – Jamel Toms Jan 02 '14 at 04:28
11

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"}
KMLong
  • 8,345
  • 2
  • 16
  • 19
  • 1
    This works very nice BUT not for nested attributes. How would one overcome that? profile_attributes added to params still throws an Unpermitted parameters: profile_attributes. I have some profile attributes in my signup form I would like to add to. – Rubytastic Sep 23 '13 at 22:29
  • 1
    Perhaps isn't necessary to specify the "if: :devise_controller", since the controller is being inherited from devise controller :) – Pablo Torrecilla Sep 26 '13 at 18:33
4

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
jtlindsey
  • 4,346
  • 4
  • 45
  • 73
2

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
Jerry Z.
  • 2,031
  • 3
  • 22
  • 28
  • And what application_controller has to do with two very concrete actions concerning user registration? Clearly, this belongs to registrations_controller – Dr.Strangelove Jul 28 '16 at 02:23
0

The problem seems with the strong parameters, look here and copy the code.

https://github.com/plataformatec/devise/blob/rails4/app/controllers/devise/registrations_controller.rb

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.

Boris Barroso
  • 1,802
  • 2
  • 22
  • 41
0

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
Ben Kreeger
  • 6,355
  • 2
  • 38
  • 53
danysz
  • 580
  • 3
  • 11