Question

I am using Rails 4.0.2, Ruby 2.0.0p353

I am trying to use strong parameters in my Rails project but I can't get the ActiveModel::ForbiddenAttributesError to appear.

If there are params that are not permitted, those params will be set to nil or 0, but I thought that the error ActiveModel::ForbiddenAttributesError should appear. So as a result, params that are not permitted by the strong parameters will be passed into my User model as nil or 0 and this is a problem for me.

Below is the following for my UsersController:

class UsersController < ApplicationController

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)

    if @user.save
      sign_in @user
      flash[:notice] = "Welcome to the league!"
      redirect_to root_url
    else
      render 'new'
    end
  end

  private
    def user_params
      params.require(:user).permit(:first_name, :last_name, :alias, 
                                   :email, :password, :password_confirmation)
    end
end

Here is the User sign-up form using, simple_form 3.0.1, new.html.erb:

<%= simple_form_for(@user) do |f| %>

  <h1>Sign Up</h1>

  <%= f.input :first_name %>
  <%= f.input :last_name %>
  <%= f.input :alias %>
  <%= f.input :email %>
  <%= f.input :password %>
  <%= f.input :password_confirmation %>
  <%= f.button :submit, class: "btn-lg btn-primary" %>
<% end %>

And here are the validations for my User model user.rb:

class User < ActiveRecord::Base

  ...

  # Validations
  validates :first_name, presence: true, length: { maximum: MAX_LENGTH_FIRST_NAME }
  validates :last_name, presence: true, length: { maximum: MAX_LENGTH_LAST_NAME }
  validates :alias, presence: true
  validates :email, presence: true,
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, length: { minimum: MIN_LENGTH_PASSWORD }

  ...

end

Now let's say that I remove :alias from user_params like so:

 private
    def user_params
      params.require(:user).permit(:first_name, :last_name, 
                                   :email, :password, :password_confirmation)
    end

From my understanding, if there is an :alias hash (or any other hash) in my :user params, then I should get the ActiveModel::ForbiddenAttributesError to appear.

So what I have tried is removing :alias from from user_params and keeping alias on the user sign up form so that I can have :alias in user_params to raise the error. In order to keep it on my form and be able to submit it, I had to comment out my alias validation in my model to like so:

 # validates :alias, presence: true

But when I create a new user with all of the fields, including alias, no error appears. Instead, I create a new user in the database with all of the information, but the alias attribute is nil no matter what I entered on the form.

If anyone could tell me how to have unpermitted params raise an exception, please let me know.

Thanks in advance.

*EDIT*

The reason I posted this was actually for an update_attributes().

My issue was that I was trying to update only 3 (out of 5) of a user's attributes. I tried to make strong parameters to make sure that only those 3 attributes were being updated and nothing else, but I guess that is the wrong way to do it.

Thanks again to Brian for the clarification on the error and how it is actually raised.

Was it helpful?

Solution

Nope, ActiveModel::ForbiddenAttributesError is only raised if you pass unsanitized objects to the record update call.

@user.update_attributes(params[:user]) # This would be an issue

User.where(params[:user]) # This would not

@user.update_attributes(user_params) # Neither would this

def user_params
  params.require(:user).permit(:name)
end

It can actually be kind of a pain, because if you forget to explicitly include an attribute, say, after a db migration, this can be a sneaky bug.

Judging by this snippet from the documentation

params = ActionController::Parameters.new(user: { name: 'Francesco', age: 22, role: 'admin' })
permitted = params.require(:user).permit(:name, :age)
permitted.permitted?      # => true
permitted.has_key?(:name) # => true
permitted.has_key?(:age)  # => true
permitted.has_key?(:role) # => false

If you really wanted an exception you could just write

ActionController::Parameters.action_on_unpermitted_parameters = :raise
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top