ruby-on-railsrubyparametersruby-on-rails-5strong-parameters

Strong Params: params.permit returns Unpermitted parameters despite whitelist


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?


Solution

  • 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.