ActiveModel::ForbiddenAttributesError when creating new user
Asked Answered
K

8

244

I have this model in Ruby but it throws a ActiveModel::ForbiddenAttributesError

class User < ActiveRecord::Base
  attr_accessor :password
  validates :username, :presence => true, :uniqueness => true, :length => {:in => 3..20}
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, :uniqueness => true, format: { with: VALID_EMAIL_REGEX }

  validates :password, :confirmation => true
  validates_length_of :password, :in => 6..20, :on => :create

  before_save :encrypt_password
  after_save :clear_password

  def encrypt_password
    if password.present?
      self.salt = BCrypt::Engine.generate_salt
      self.encrypted_password= BCrypt::Engine.hash_secret(password, salt)
    end
  end

  def clear_password
    self.password = nil
  end
end

when I run this action

  def create
    @user = User.new(params[:user])
    if @user.save
      flash[:notice] = "You Signed up successfully"
      flash[:color]= "valid"
    else
      flash[:notice] = "Form is invalid"
      flash[:color]= "invalid"
    end
    render "new"
  end

on ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux].

Can you please tell me how to get rid of this error or establish a proper user registration form?

Karelian answered 27/6, 2013 at 5:41 Comment(4)
try with adding attr_accessible :password, :password_confirmation,:user_name, :email, :your-other-attributes in the User modelGlomerule
Add strong_parameter gem to use attr_accessible.Deannedeans
strong parameters to use attr_accessible?!Philemon
I believe @BruceLi meant: Add the protected_attributes gem to use attr_accessible.Idealist
D
433

I guess you are using Rails 4. If so, the needed parameters must be marked as required.

You might want to do it like this:

class UsersController < ApplicationController

  def create
    @user = User.new(user_params)
    # ...
  end

  private

  def user_params
    params.require(:user).permit(:username, :email, :password, :salt, :encrypted_password)
  end
end
Dupion answered 27/6, 2013 at 6:21 Comment(4)
Is there any documentation about why this works or why this is needed?Borrego
@OmarJackman The functionality is provided by the strong_parameter gem. It is covered in Rails Guides: guides.rubyonrails.org/….Dupion
People might be experiencing this if they use CanCan with Rails 4.0. Try AntonTrapps's rather clean workaround solution until CanCan gets updated.Rok
@Rok Would you please post this as a separate answer? I missed it the first time through, but it still saved me a ton of time.Cadmus
R
65

For those using CanCan. People might be experiencing this if they use CanCan with Rails 4+. Try AntonTrapps's rather clean workaround solution here until CanCan gets updated:

In the ApplicationController:

before_filter do
  resource = controller_name.singularize.to_sym
  method = "#{resource}_params"
  params[resource] &&= send(method) if respond_to?(method, true)
end

and in the resource controller (for example NoteController):

private
def note_params
  params.require(:note).permit(:what, :ever)
end

Update:

Here's a continuation project for CanCan called CanCanCan, which looks promising:

CanCanCan

Rok answered 12/9, 2013 at 14:8 Comment(2)
Thanks!! I have a question, with CanCanCan (active) is solved or not need this code?Characharabanc
For me, CanCanCan still have the issue. Not using load_resource or use load_resource :except => :create solved the issue. Check the original answer hereErode
G
29

For those using CanCanCan:

You will get this error if CanCanCan cannot find the correct params method.

For the :create action, CanCan will try to initialize a new instance with sanitized input by seeing if your controller will respond to the following methods (in order):

  1. create_params
  2. <model_name>_params such as article_params (this is the default convention in rails for naming your param method)
  3. resource_params (a generically named method you could specify in each controller)

Additionally, load_and_authorize_resource can now take a param_method option to specify a custom method in the controller to run to sanitize input.

You can associate the param_method option with a symbol corresponding to the name of a method that will get called:

class ArticlesController < ApplicationController
  load_and_authorize_resource param_method: :my_sanitizer

  def create
    if @article.save
      # hurray
    else
      render :new
    end
  end

  private

  def my_sanitizer
    params.require(:article).permit(:name)
  end
end

source: https://github.com/CanCanCommunity/cancancan#33-strong-parameters

Ginsburg answered 6/2, 2017 at 14:42 Comment(2)
Thanks. This was my problem. I refactored a model but left the params method the old name. Renamed and fixed the issue.Shote
Thanks. This saved me😅Attract
J
25

There is an easier way to avoid the Strong Parameters at all, you just need to convert the parameters to a regular hash, as:

unlocked_params = ActiveSupport::HashWithIndifferentAccess.new(params)

model.create!(unlocked_params)

This defeats the purpose of strong parameters of course, but if you are in a situation like mine (I'm doing my own management of allowed params in another part of my system) this will get the job done.

Jurdi answered 14/4, 2015 at 18:7 Comment(1)
Doesn't work in rails 6, exception: unable to convert unpermitted parameters to hash Arvad
W
24

If using ActiveAdmin don't forget that there is also a permit_params in the model register block:

ActiveAdmin.register Api::V1::Person do
  permit_params :name, :address, :etc
end

These need to be set along with those in the controller:

def api_v1_person_params
  params.require(:api_v1_person).permit(:name, :address, :etc)
end

Otherwise you will get the error:

ActiveModel::ForbiddenAttributesError
Witless answered 26/3, 2014 at 17:55 Comment(0)
A
3

Alternatively you can use the Protected Attributes gem, however this defeats the purpose of requiring strong params. However if you're upgrading an older app, Protected Attributes does provide an easy pathway to upgrade until such time that you can refactor the attr_accessible to strong params.

Adolescence answered 22/7, 2013 at 2:30 Comment(0)
C
2

One more reason is that you override permitted_params by a method. For example

def permitted_params
   params.permit(:email, :password)
end
Colis answered 5/9, 2021 at 12:24 Comment(0)
H
0

If you are on Rails 4 and you get this error, it could happen if you are using enum on the model if you've defined with symbols like this:

class User
  enum preferred_phone: [:home_phone, :mobile_phone, :work_phone]
end

The form will pass say a radio selector as a string param. That's what happened in my case. The simple fix is to change enum to strings instead of symbols

enum preferred_phone: %w[home_phone mobile_phone work_phone]
# or more verbose
enum preferred_phone: ['home_phone', 'mobile_phone', 'work_phone']
Hadden answered 28/1, 2020 at 20:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.