Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby on Rails - PUT Method Creates Extra Params Entry

So I observed some weird behaviour while implementing an endpoint for a RESTful API I am creating for a mobile client. I am using a PUT method to update an attribute on the User model. I send the user's id as a URL parameter and the value to update inside a JSON object. Everything seems to work just fine but when I check the parameters via the rails logs I noticed something strange. For some reason there is an extra parameter being sent to the backend that I can't seem to explain. Here are the logs I am seeing when I call this endpoint from the mobile client:

Parameters: {"enable_security"=>true, "id"=>"7d7fec98-afba-4ca9-a102-d5d71e13f6ce", "user"=>{}}

As can be seen above an additional "user"=>{} is appended to the list of parameter entries. I see this when I print out the params object as well. I can't seem to explain where this is coming from. I also checked the mobile client just to be safe and there is no where in code where I send a parameter with a key user. This is very puzzling to me and makes me think I am missing something fairly simple. Why is there an empty object with the user key being sent to the backend RESTful API?

Update to Provide More Information

Here is the code that gets called when the user hits the endpoint that updates the user User model:

  #PUT /:id/user/update_security_settings
  def update_security_settings
    @user = User.find_by_id(params[:id])
    @user.advanced_security_enabled = params[:enable_security]

    respond_to do |format|
      if @user.save
        response = {:status => "200", :message => "User's security settings updated."}
        format.json { render json: response, status: :ok }
      else
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

Update in Response to User's Comments

Here are the routes that pertain to the user_controller, the view controller that defines all endpoints that deal with creating and updating the User model.

post '/user/upload_profile', to: 'user#upload_profile'
get '/:id/user', to: 'user#find_user'
put '/:id/user/update_security_settings', to: 'user#update_security_settings'
resources :user, :defaults => { :format => 'json' }
like image 947
ScottOBot Avatar asked Sep 18 '25 06:09

ScottOBot


1 Answers

Does this comment really mirror your actual route?

#PUT /:id/user/update_security_settings

I'd expect it to be /user/:id/update_security_settings instead.

Can you show us your config/routes.rb - My wild guess is that your routes are somehow configured to expect an actual nested user param, which you don't send (of course) and therefor appears empty in the logs.

Update: Some of your routes are unusual. You actually don't need the find_user route as it should be covered under resources :user as show action (provided you defined a show method in your controller, which is the default way to retrieve a single resource item; so no need for find_user)

For custom routes like your update_security_settings action I'd suggest to stick to the default pattern, like resource/:id/actionand nesting it in the default resourceful route. Putting the id before the resource is very unusual, confusing and may actually be related to your issue (thoguh I#m not sure about that). Try cleaning up your routes.rb liek this:

# notice that resources expects the plural form :users
resources :users do
  member do 
    patch :update_security_settings
    post :upload_profile
    # any other custom routes
  end
end

This will result in routes like GET /users (index), GET /users/1 (show) and PATCH /users/1/update_security_settings.

More on routing an be found here: Rails Guides | Routing From The Outside In

Please check if the changes above remove your empty user param.

like image 95
Michael Feihstel Avatar answered Sep 20 '25 21:09

Michael Feihstel