6

UsersProfileController has strong params that looks like so:

    def user_profile_params
      params.permit(:age, :relations)
      # yes, I am not requiring user_profile. Just permitting attributes I need. 
    end

The create action builds UserProfile through a parent (has-one and belongs-to association)

    def create
      parent = Parent.create_guest
      parent.build_user_profile(user_profile_params)
      if parent.save 
        # do something 
      else 
        # handle error
      end
    end

Calling params in UserProfiles returns:

    <ActionController::Parameters 
      {"age"=>"23", 
       "relations"=>"3", 
       "subdomain"=>"api", 
       "format"=>:json, 
       "controller"=>"api/v1/user_profiles", 
       "action"=>"create"} 
     permitted: false>

Calling user_profile_params, returns this:

    user_profile_params:
      Unpermitted parameters: subdomain, format
      <ActionController::Parameters 
       {"age"=>"23", 
       "relations"=>"3", } 
      permitted: true>

When a post request comes in, I expect to be able to create user_profile using the whitelisted params in user_profile_params. Instead, the create action in UserProfiles fails with error: Unpermitted parameters: subdomain, format.

This isn't what I expected. I expected user_profile_params to only include the permitted values and ignore all others.

I could add :format and :subdomain to list of permitted attributes but something feels a bit off about that.

Can someone explain what is going on/what I am missing?

Uzzar
  • 705
  • 1
  • 12
  • 24
  • It appears to me that you are not actually passing through that create block in your UsersProfileController. – Chris Moody Jan 21 '17 at 00:54
  • @ChrisMoody: Not sure I understand what you mean. If you mean the method doesn't get called, then that isn't true. Was able to step into the `create` action in the UsersProfileController and found that error occurs when `user_profile_params` is called on this specific line `parent.build_user_profile(user_profile_params)`. Can you explain what you mean? – Uzzar Jan 21 '17 at 01:00

2 Answers2

7

This message is just a warning, and not an error/exception. If your model it's not being persisted, that's by another reason.

From the strong parameters docs:

Handling of Unpermitted Keys

By default parameter keys that are not explicitly permitted will be logged in the development and test environment. In other environments these parameters will simply be filtered out and ignored.

Additionally, this behaviour can be changed by changing the config.action_controller.action_on_unpermitted_parameters property in your environment files. If set to :log the unpermitted attributes will be logged, if set to :raise an exception will be raised.

You can simulate it in your console (rails c):

fake_params_hash = {
    "age"=>"23", 
    "relations"=>"3", 
    "subdomain"=>"api", 
    "format"=>:json, 
    "controller"=>"api/v1/user_profiles", 
    "action"=>"create"
} 

permited_params = ActionController::Parameters.new(fake_params_hash).permit(:age, :relations)
#=> Unpermitted parameters: subdomain, format <== warning logged to the console
#=> <ActionController::Parameters {"age"=>"23", "relations"=>"3"} permitted: true>


user = User.create(permited_params) #mass assigment with permited params

#check if there are errors
puts user.errors.messages if user.errors.any?

As you can see, this message is not thrown by the User.create, but when .permit is invoked.

mrlew
  • 7,078
  • 3
  • 25
  • 28
  • 1
    You are correct. Was actually coming to post that the error was due to validation on `User` model. Thanks for taking time out to answer:) – Uzzar Jan 21 '17 at 02:58
2

Expanding on @mrlew's answer, if we have an array, we need to permit the parameters inside the array. Otherwise, the warning message will keep showing.

fake_params_hash = {
    "age"=>"23",
    "relations"=>"3",
    "subdomain"=>"api",
    "format"=>:json,
    "array"=>[
        "sub_item"=>"hello"
    ],
    "controller"=>"api/v1/user_profiles",
    "action"=>"create"
}

permited_params = ActionController::Parameters.new(fake_params_hash).permit(:age, :relations, :array)

#=> Unpermitted parameters: :subdomain, :format, :array

permited_params = ActionController::Parameters.new(fake_params_hash).permit(:age, :relations, array: [:sub_item])

#=> Unpermitted parameters: :subdomain, :format

It took me half a day to realise this in order to solve a bug at work...

Damian Demasi
  • 71
  • 1
  • 6